算法描述
略去部分诸如链表为空的细节。带数字的图示容易理解,一般情况的抽象图示就偷懒没画了。(画这个还挺累的,为了表达清楚,尝试了好几种不同的图示方案,希望下面的能容易理解。)
-
不改变各个节点的数据域,只通过改变两个链表的指针域,来拼接成新的链表。所以新链表的头指针指向的是两个链表中头节点数据较小的一个。因而,第一步,应先将头指针确定。
-
引入两个指针:pnew=指向已成型的新链表的尾部;px指向另一个链表的头部。比如,如图,初始的pnew应当指向数据域为1的结点,而px指向另一个链表的头节点。因为,px节点的后继节点的值必定大于px节点的值。(单个链表本身是升序的)
-
如果pnew->next节点值小于或等于px,则pnew=pnew->next,直到后继节点值大于px :
-
将pnew的后继指针指向px,即将px插在新链表的尾部,该节点就变成新链表的尾部了,pnew指向该节点,而原来的pnew的后继节点,因为与前部分链表断开,成为头部,px指向该节点。
-
如此交替插在新链表的尾部,直到pnew指针遍历完某个链表,就可以将pnew后继指针指向px节点,然后返回头指针了。(px是不会动的,判断pnew指针所指的链表是否遍历完即可)
示例代码
struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2){
struct ListNode *head,*pnew,*px,*temp;
if(list1==NULL)return list2; //---------
if(list2==NULL)return list1; //检查链表是否为空
if(list1->data>=list2->data){ //初始化操作:确定头节点与两个指针的位置
head=list2;
pnew=list2;
px=list1;
}
else{
head=list1;
pnew=list1;
px=list2;
}
while(1){ //交替拼接
while(pnew->next!=NULL && pnew->next->data <= px->data){ //确定px与pnew的交接位置
pnew=pnew->next;
}
if(pnew->next==NULL){//判断pnew是否遍历完所在链表,如是便可返回头节点,否则交换指针
pnew->next=px;
return head;
}
else{ //交换指针
temp=pnew->next;
pnew->next=px;
pnew=px;
px=temp;
}
}
}
有常规算法,各方面更方便一些。当时把问题复杂化了。
三个指针:两个分别用来遍历两个链表(p1
,p2
),另一个操作生成新链表(pnew
);
每次循环用对比p1
与p2
所指结点,取两者中符合顺序的一个,接在新链表上,被取值的指针向前移,直到有链表遍历完成,接上剩余的另一个链表即可。20.3.27注