題目描述:
給定乙個亂序的單鏈表的頭節點,對該鍊錶中的節點進行排序
要求時間複雜度為o(nlgn),空間複雜度為o(1)
分析:
由於題目要求時間複雜度我o(nlgn),因此選擇排序和插入排序可以排除。
在排序演算法中,時間複雜度為o(nlgn)的主要有:歸併排序、快速排序、堆排序。
其中堆排序的空間複雜度為(n),也不符合要求,因此也可以排除。
歸併排序在對陣列進行排序時,需要乙個臨時陣列來儲存所有元素,空間複雜度為o(n)。但是利用歸併演算法對單鏈表進行排序時,可以通過next指標來記錄元素的相對位置,因此時間複雜度也為o(1)。
因此可以考慮用快排和歸併來實現單鏈表的排序。
快速排序:
快速排序的主要思想是:
1)選定乙個基準元素
2)經過一趟排序,將所有元素分成兩部分
3)分別對兩部分重複上述操作,直到所有元素都已排序成功
因為單鏈表只能從煉表頭節點向後遍歷,沒有prev指標,因此必須選擇頭節點作為基準元素。這樣第二步操作的時間複雜度就為o(n)。由於之後都是分別對兩部分完成上述操作,因此會將鍊錶劃分為lgn個段,因此時間複雜度為o(nlgn)
void swap(int
*a,int
*b) listnode *partion(listnode *pbegin,listnode *pend)
q=q->next;
}swap(&p->val,&pbegin->val);
return p;
}void quick_sort(listnode *pbegin,listnode *pend)
listnode* sortlist(listnode* head)
歸併排序:
歸併排序的也是基於分治的思想,但是與快排不同的是歸併是先劃分,然後從底層開始向上合併。
歸併排序的主要思想是將兩個已經排好序的分段合併成乙個有序的分段。除了找到中間節點的操作必須遍歷鍊錶外,其它操作與陣列的歸併排序基本相同。
listnode* merge_sort(listnode* head)
listnode* merge(listnode* head1, listnode* head2) //合併兩個有序鍊錶
else
newtail = newtail->next;
newtail->next =
null;
}if(head1) newtail->next = head1;
if(head2) newtail->next = head2;
return newhead->next; //煉表頭節點
}listnode* getmid(listnode* head) //獲取中間節點並分段
prev->next =
null; //將鍊錶分為兩段
return slow;
}
因此歸併排序的關鍵在於將單鏈表變為兩個排序好的分段。 單鏈表排序 快排 歸併排序
題目描述 給定乙個亂序的單鏈表的頭節點,對該鍊錶中的節點進行排序 要求時間複雜度為o nlgn 空間複雜度為o 1 分析 由於題目要求時間複雜度我o nlgn 因此選擇排序和插入排序可以排除。在排序演算法中,時間複雜度為o nlgn 的主要有 歸併排序 快速排序 堆排序。其中堆排序的空間複雜度為 n...
單鏈表排序 快排和歸併排序
題目描述 給定乙個亂序的單鏈表的頭節點,對該鍊錶中的節點進行排序 要求時間複雜度為o nlgn 空間複雜度為o 1 分析 由於題目要求時間複雜度我o nlgn 因此選擇排序和插入排序可以排除。在排序演算法中,時間複雜度為o nlgn 的主要有 歸併排序 快速排序 堆排序。其中堆排序的空間複雜度為 n...
快排 歸併排序
二 歸併排序 遞迴 分治的思維 分治 確定分界點 我們下面以中間值q l r 1 為分界點,理論上任何點作為分界點都可 調整區間 x 的在左邊,x的在右邊 兩個區間 遞迴 遞迴處理左右兩段 原題鏈結 題目描述 給定你乙個長度為n的整數數列。請你使用快速排序對這個數列按照從小到大進行排序。並將排好序的...