題目:單鏈表的歸並排序,返回排序后的鏈表。傳統的歸並都是數組,可以隨機訪問元素,鏈表則需要順序遍歷找中間結點。
思路:
設置兩個指針,一個步長為1, 一個步長為2,當快指針到達尾結點時,慢指針指向中間結點,時間復雜度為O(N);
平分為左鏈表L1和右鏈表L2,遞歸分裂,直到鏈表為空或者只有一個結點;
將鏈表L2的每個結點插入到鏈表L1中,時間復雜度為O(m+n),m、n分別為兩條鏈表的長度。
畫出遞歸樹,可知總的時間復雜度為O(N * lgN)。
代碼:
合並兩個有序的鏈表:
1 struct ListNode 2 { 3 int value; 4 ListNode *next; 5 ListNode(int v): value(v), next(NULL) 6 { 7 } 8 }; 9
10 ListNode *mergeSortedList(ListNode *L1, ListNode *L2) 11 { 12 ListNode dummy(-1), *p1 = &dummy, *p2 = L2; //L1的輔助頭結點dummy,因為可能在頭部插入
13 dummy.next = L1; 14 while(p1->next != NULL && p2 != NULL) //停止條件,也包括了判斷兩個鏈表是否為空
15 { 16 if(p1->next->value >= p2->value) 17 { 18 L2 = p2->next; 19 p2->next = p1->next; 20 p1->next = p2; 21 p1 = p2; 22 p2 = L2; 23 } 24 else
25 { 26 p1 = p1->next; 27 } 28 } 29 if(p1->next == NULL) //L2可能還有未處理的結點,直接加在L1尾部即可
30 { 31 p1->next = p2; 32 } 33
34 return dummy.next; 35 }
單鏈表的歸並排序:
1 ListNode *listMergeSort(ListNode *head) 2 { 3 if(head == NULL || head->next == NULL) //鏈表為空,或者只有一個結點,直接返回
4 return head; 5
6 ListNode *slow = head, *fast = head; 7 while(fast->next != NULL && fast->next->next != NULL) 8 { 9 fast = fast->next->next; 10 slow = slow->next; 11 } 12
13 ListNode *leftHead = head, *rightHead = slow->next; 14 slow->next = NULL; //需要把左半鏈表的尾結點的next賦空值,所以用一個變量來記錄右半鏈表的頭
15
16 leftHead = listMergeSort(leftHead); 17 rightHead = listMergeSort(rightHead); 18
19 return mergeSortedList(leftHead, rightHead); 20 }