1. 程式人生 > >已知兩個連結串列head1 和head2 各自有序,請把它們合併成一個連結串列依然有序。使用非遞迴方法以及遞迴方法。

已知兩個連結串列head1 和head2 各自有序,請把它們合併成一個連結串列依然有序。使用非遞迴方法以及遞迴方法。

首先介紹非遞迴方法。因為兩個連結串列head1 和head2都是有序的,所以我們只需要找把較短連結串列的各個元素有序的插入到較長的連結串列之中就可以了。
原始碼如下:
1 node* insert_node(node *head, node *item) //head != NULL
2 {
3 node *p = head;
4 node *q = NULL; //始終指向p之前的節點
5   
6 while(p->data < item->data && p != NULL)
7 {
8 q = p;
9 p = p->next;
10 }
11 if (p == head) //插入到原頭節點之前
12 {
13 item->next = p;
14 return item;
15 }
16 //插入到q與p之間之間
17 q->next = item;
18 item->next = p;
19 return head;
20 }
21   
22
23 node* merge(node* head1, node* head2)
24 {   
25 node* head; //合併後的頭指標
26 node *p;   
27 node *nextP; //指向p之後
28   
29 if ( head1 == NULL ) //有一個連結串列為空的情況,直接返回另一個連結串列
30 {
31 return head2;
32 }
33 else if ( head2 == NULL )
34 {
35 return head1;
36 }
37   
38 // 兩個連結串列都不為空
39 if(length(head1) >= length(head2)) //選取較短的連結串列
40 { //這樣進行的插入次數要少些
41 head = head1;
42 p = head2;
43 }
44 else
45 {
46 head = head2;
47 p = head1;
48 }
49   
50 while(p != NULL)
51 {
52 nextP = p->next; //儲存p的下一個節點
53 head = insert_node(head, p); //把p插入到目標連結串列中
54 p = nextP; //指向將要插入的下一個節點
55 }
56   
57 return head;
58 }
這裡insert_node()函式是有序的插入節點,注意與前面例題中的函式有區別,這裡它傳入的引數是node*型別。然後在merge()函式中(程式碼52~55行)迴圈把短連結串列中的所有節點插入到長連結串列中。
接下來介紹非遞迴方法。比如有下面兩個連結串列:
連結串列1:1->3->5
連結串列2:2->4->6
遞迴方法的步驟如下:
(1)比較連結串列1和連結串列2的第一個節點資料,由於1<2,因此把結果連結串列頭節點指向連結串列1中的第一個節點,即資料1所在的節點。
(2)對剩餘的連結串列1(3->5)和連結串列2再呼叫本過程,比較得到結果連結串列的第二個節點,即2與3比較得到2。此時合併後的連結串列節點為1->2。
接下來的過程類似(2),如此遞迴知道兩個連結串列的節點都被加到結果連結串列中。
1 node * MergeRecursive(node *head1, node *head2)
2 {
3 node *head = NULL;
4   
5 if (head1 == NULL)
6 {
7 return head2;
8 }
9 if (head2 == NUL)
10 {
11 return head1;
12 }
13   
14 if ( head1->data < head2->data )
15 {
16 head = head1 ;
17 head->next = MergeRecursive(head1->next,head2);
18 }
19 else
20 {
21 head = head2 ;
22 head->next = MergeRecursive(head1,head2->next);
23 }
24   
25 return head ;
26 }