链表合并是数据结构中的经典问题,在算法面试和实际开发中经常出现。本文将深入解析如何高效合并两个有序链表,并展示C语言的实现方案。

给定两个升序排列的链表list1和list2,要求将它们合并为一个新的升序链表并返回。新链表应该通过拼接给定链表的节点来完成。
示例:
输入:list1 = [1,2,4], list2 = [1,3,4]
输出:[1,1,2,3,4,4]基本思想:
时间复杂度: O(n+m),其中n和m分别是两个链表的长度 空间复杂度: O(1),不需要额外空间,直接在原节点上操作
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
struct ListNode* l1 = list1;
struct ListNode* l2 = list2;
struct ListNode* NewHead = NULL;
struct ListNode* NewTail = NULL;
// 处理空链表的情况
if (l1 == NULL) return l2;
if (l2 == NULL) return l1;
// 遍历两个链表
while (l1 && l2) {
if (l1->val < l2->val) {
// 处理新链表的头节点
if (NewHead == NULL) {
NewHead = NewTail = l1;
} else {
NewTail->next = l1;
NewTail = NewTail->next;
}
l1 = l1->next;
} else {
// 处理新链表的头节点
if (NewHead == NULL) {
NewHead = NewTail = l2;
} else {
NewTail->next = l2;
NewTail = NewTail->next;
}
l2 = l2->next;
}
}
// 连接剩余链表
if (l1 == NULL) {
NewTail->next = l2;
} else {
NewTail->next = l1;
}
return NewHead;
}if (l1 == NULL) return l2;
if (l2 == NULL) return l1;这两行代码处理了空链表的边界情况,提高了代码的健壮性。
if (NewHead == NULL) {
NewHead = NewTail = l1; // 或l2
}这里使用NewHead和NewTail两个指针分别记录新链表的头和尾:
NewHead:始终指向新链表的头节点NewTail:始终指向新链表的尾节点,便于尾插操作if (l1->val < l2->val) {
// 插入l1节点
} else {
// 插入l2节点
}通过比较两个链表当前节点的值,决定哪个节点应该优先插入新链表,确保结果保持升序。
if (l1 == NULL) {
NewTail->next = l2;
} else {
NewTail->next = l1;
}当任一链表遍历完后,直接将另一链表的剩余部分连接到新链表尾部,避免了不必要的循环。
在原始代码中,存在一个典型错误:
// 错误写法(赋值而非比较)
if(NewHead=NULL)
// 正确写法(比较操作)
if(NewHead == NULL)这个错误会导致:
NewHead设置为NULLNULL相当于0)开发建议: 在条件判断中使用常量在前的方式避免此类错误:
if (NULL == NewHead) // 如果误写为赋值,编译器会报错使用哨兵节点可以进一步简化代码逻辑:
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
struct ListNode dummy; // 哨兵节点
struct ListNode* tail = &dummy;
dummy.next = NULL;
while (list1 && list2) {
if (list1->val < list2->val) {
tail->next = list1;
list1 = list1->next;
} else {
tail->next = list2;
list2 = list2->next;
}
tail = tail->next;
}
// 连接剩余部分
tail->next = list1 ? list1 : list2;
return dummy.next; // 哨兵的下一个节点即真实头节点
}哨兵节点方案的优点:
合并两个有序链表是链表操作中的基础但重要的算法:
多路归并*:多个有序流的合并(如K个有序链表) 3. 数据库系统:合并多个有序结果集 4. 消息队列:合并多个有序消息流
合并两个有序链表是链表操作中的基础但重要的算法: