對連結串列進行排序(不能額外空間,時間為O(NL))
阿新 • • 發佈:2019-02-11
Sort a linked list in O(n log n) time using constant space complexity.
對一個連結串列進行排序,且時間複雜度要求為 O(n log n) ,空間複雜度為常量。一看到 O(n log n) 的排序,首先應該想到歸併排序和快速排序,但是通常我們使用這兩種排序方法時都是針對陣列的,現在是連結串列了。
歸併排序法:在動手之前一直覺得空間複雜度為常量不太可能,因為原來使用歸併時,都是 O(N)的,需要複製出相等的空間來進行賦值歸併。對於連結串列,實際上是可以實現常數空間佔用的。利用歸併的思想,遞迴地將當前連結串列分為兩段,然後merge,分兩段的方法是使用 fast-slow 法,用兩個指標,一個每次走兩步,一個走一步,知道快的走到了末尾,然後慢的所在位置就是中間位置,這樣就分成了兩段。merge時,把兩段頭部節點值比較,用一個 p 指向較小的,且記錄第一個節點,然後 兩段的頭一步一步向後走,p也一直向後走,總是指向較小節點,直至其中一個頭為NULL,處理剩下的元素。最後返回記錄的頭即可。程式碼如下:
[cpp] view
plaincopyprint?
快速排序:使用快排也行,就是每次利用頭節點作為基準,將小於它的交換到連結串列左側,大於它的放在右側,最後把它換到中間某個位置,然後遞迴處理左側和右側。但是相對於歸併來說,它的元素交換次數太多了,可能會超時。
- class Solution {
- public:
- ListNode *sortList(ListNode *head) {
- if(!head||!head->next)
- return head;
- return mergeSort(head);
- }
- ListNode * mergeSort(ListNode *head){
-
if(!head||!head->next) //just one element
- return head;
- ListNode *p=head, *q=head, *pre=NULL;
- while(q&&q->next!=NULL){
- q=q->next->next;
- pre=p;
- p=p->next; //divide into two parts
- }
- pre->next=NULL;
-
ListNode *lhalf=mergeSort(head);
- ListNode *rhalf=mergeSort(p); //recursive
- return merge(lhalf, rhalf); //merge
- }
- ListNode * merge(ListNode *lh, ListNode *rh){
- ListNode *temp=new ListNode(0);
- ListNode *p=temp;
- while(lh&&rh){
-
if(lh->val<=rh->val){
- p->next=lh;
- lh=lh->next;
- }
- else{
- p->next=rh;
- rh=rh->next;
- }
- p=p->next;
- }
- if(!lh)
- p->next=rh;
- else
- p->next=lh;
- p=temp->next;
- temp->next=NULL;
- delete temp;
- return p;
- }
- };
快速排序:使用快排也行,就是每次利用頭節點作為基準,將小於它的交換到連結串列左側,大於它的放在右側,最後把它換到中間某個位置,然後遞迴處理左側和右側。但是相對於歸併來說,它的元素交換次數太多了,可能會超時。