說明:本文僅供學習交流,轉載請標明出處,歡迎轉載!
題目:已知有兩個有序的單鏈表,其頭指針分別為head1和head2,實現將這兩個鏈表合並的函數:
Node* ListMerge(Node *head1,Node *head2)
這個算法很像我們排序算法中的歸並排序,只能說“很像”,因為思想是一樣的,但是這個與歸並排序還是有區別的,區別如下:
1.歸並排序是針對有序數組,而這里是有序鏈表;
2.歸並排序排序的時間復雜度為o(nlogn),而這里的時間復雜度最壞情況下為O(m+n),最好的情況下為O(min{m,n})。
3.歸並排序需要重新申請空間,而這里無需再重新申請空間,只需改變鏈表結點的指針指向。
而這里算法的思想跟歸並排序是一樣的,都是對兩個待歸並的線性表分別設置1個指針,比較這兩個當前指針的大小,將小的結點加入到合並后的線性表中,並向后移動當前指針。若兩個線性表中,至少有一個表掃描完,走將對應的另一個表之間整體添加到合並后的線性表中。在這里:鏈表和數組的區別在於,鏈表只需要改變當前合並序列尾指針的位置,而數組則要將剩下的值依次復制到歸並表的尾部。
算法的遞歸實現如下:
- Node *ListMerge1(Node *head1,Node *head2)//采用遞歸的方法實現
- {
- if(head1==NULL)
- return head2;
- if(head2==NULL)
- return head1;
- Node *head=NULL;
- if(head1->value < head2->value)
- {
- head=head1;
- head->next=ListMerge1(head1->next,head2);
- }
- else
- {
- head=head2;
- head->next=ListMerge1(head1,head2->next);
- }
- return head;
- }
算法的非遞歸實現如下:
- Node *ListMerge(Node *head1,Node *head2)
- {
- if(!head1) return head2;
- if(!head2) return head1;
- Node *head=NULL;//合並后的頭指針
- Node *p1=head1;//p1用於掃描鏈表1
- Node *p2=head2;//p2用於掃描鏈表2
- if(head1->value<head2->value)
- {
- head=head1;
- p1=head1->next;
- }
- else
- {
- head=head2;
- p2=head2->next;
- }
- Node *p=head;//p永遠指向最新合並的結點
- while(p1 && p2)//如果循環停止,則p1或p2至少有一個為NULL
- {
- if(p1->value<p2->value)
- {
- p->next=p1;
- p1=p1->next;
- }
- else
- {
- p->next=p2;
- p2=p2->next;
- }
- p=p->next;
- }
- if(p1)//如果鏈1還沒走完
- {
- p->next=p1;
- }
- else if(p2)//如果鏈2還沒走完
- {
- p->next=p2;
- }
- return head;
- }
整個測試代碼如下:
- #include<iostream>
- using namespace std;
- struct Node
- {
- int value;
- Node* next;
- Node(int v):value(v){}
- };
- /*創建一個鏈表,1->2->3->4->5->6->7*/
- Node* CreateList1()//創建一個有序的單鏈表1
- {
- Node *head;
- Node *n1=new Node(1);
- Node *n3=new Node(3);
- Node *n5=new Node(5);
- Node *n7=new Node(7);
- Node *n9=new Node(9);
- head=n1;
- n1->next=n3;
- n3->next=n5;
- n5->next=n7;
- n7->next=n9;
- n9->next=NULL;
- return head;
- }
- Node* CreateList2()//創建一個有序的單鏈表2
- {
- Node *head;
- Node *n2=new Node(2);
- Node *n4=new Node(4);
- Node *n6=new Node(6);
- Node *n8=new Node(8);
- head=n2;
- n2->next=n4;
- n4->next=n6;
- n6->next=n8;
- n8->next=NULL;
- return head;
- }
- void FreeList(Node *head)//將鏈表空間釋放
- {
- if(head==NULL)
- {
- return ;
- }
- else
- {
- Node *temp=head->next;
- delete head;
- head=temp;
- FreeList(head);
- }
- }
- void VisitList(Node *head)//遍歷鏈表中的元素,用遞歸的方法遍歷
- {
- if(head)
- {
- cout<<head->value<<"->";
- VisitList(head->next);
- }
- else
- {
- cout<<"null"<<endl;
- }
- }
- Node *ListMerge(Node *head1,Node *head2)
- {
- if(!head1) return head2;
- if(!head2) return head1;
- Node *head=NULL;//合並后的頭指針
- Node *p1=head1;//p1用於掃描鏈表1
- Node *p2=head2;//p2用於掃描鏈表2
- if(head1->value<head2->value)
- {
- head=head1;
- p1=head1->next;
- }
- else
- {
- head=head2;
- p2=head2->next;
- }
- Node *p=head;//p永遠指向最新合並的結點
- while(p1 && p2)//如果循環停止,則p1或p2至少有一個為NULL
- {
- if(p1->value<p2->value)
- {
- p->next=p1;
- p1=p1->next;
- }
- else
- {
- p->next=p2;
- p2=p2->next;
- }
- p=p->next;
- }
- if(p1)//如果鏈1還沒走完
- {
- p->next=p1;
- }
- else if(p2)//如果鏈2還沒走完
- {
- p->next=p2;
- }
- return head;
- }
- Node *ListMerge1(Node *head1,Node *head2)//采用遞歸的方法實現
- {
- if(head1==NULL)
- return head2;
- if(head2==NULL)
- return head1;
- Node *head=NULL;
- if(head1->value < head2->value)
- {
- head=head1;
- head->next=ListMerge1(head1->next,head2);
- }
- else
- {
- head=head2;
- head->next=ListMerge1(head1,head2->next);
- }
- return head;
- }
- int main()
- {
- Node *head1=CreateList1();
- Node *head2=CreateList2();
- cout<<"歸並前"<<endl;
- cout<<"鏈表1:";
- VisitList(head1);
- cout<<"鏈表2:";
- VisitList(head2);
- cout<<"合並后的鏈表:";
- //Node *head=ListMerge(head1,head2);
- Node *head=ListMerge1(head1,head2);
- VisitList(head);
- FreeList(head);
- return 0;
- }
測試結果如下:
參考資料-------------《劍指offer》