将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = [] 输出:[]
示例 3:
输入:l1 = [], l2 = [0] 输出:[0]
提示:
- 两个链表的节点数目范围是
[0, 50]
-100 <= Node.val <= 100
l1
和l2
均按 非递减顺序 排列
实战:
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
if (list1==NULL)return list2;
if (list2==NULL)return list1;
ListNode* l1, *l2;
ListNode* newhead, *newtail;
newhead = newtail = (ListNode*)malloc(sizeof (ListNode));
l1 = list1,l2 = list2;
while (l1&&l2){
if (l1->val>=l2->val){
newtail->next=l2;
newtail=newtail->next;
l2=l2->next;
}else{
newtail->next=l1;
newtail=newtail->next;
l1=l1->next;
}
}
if(l1){
newtail->next=l1;
}
if(l2){
newtail->next=l2;
}
return newhead->next;
}
以下是代码中关于newhead
的操作:
ListNode* newhead, *newtail; // 给新链表的开辟一个哨兵位
newhead = newtail = (ListNode*)malloc(sizeof(ListNode));
这里,newhead
和newtail
都被指向了同一块新分配的内存,这块内存是为哨兵节点准备的。由于是新分配的,哨兵节点的值默认是未初始化的,即它可能是任意值。
在链表合并的逻辑中,newtail
始终指向新链表的最后一个节点的下一个位置,而newhead
始终指向新链表的起始位置(即哨兵节点)。由于哨兵节点不包含有效数据,最终返回的是newhead->next
,这样返回的就是合并后链表的第一个有效节点。
在合并过程中,从未向newhead
节点本身赋值,它只是作为一个占位符存在。所有合并进来的节点都是通过newtail->next
来链接的,而newtail
则是在每次合并操作后更新为新添加节点的下一个节点。
最终,当合并操作完成,如果l1
或l2
还有剩余节点,它们会被直接链接到newtail->next
上。这时,newhead->next
将指向合并后链表的第一个有效节点,而newhead
节点本身将被丢弃(因为它不包含任何有效数据)。
在合并完成后,哨兵节点newhead
的作用就完成了,返回newhead->next
作为合并后链表的头节点,而原始的list1
和list2
的头节点则被适当地链接到了新链表中。