快速排序的挖坑法與prev、cur法,咱們在上一篇博客的第6個排序中講的很是詳細,http://10740184.blog.51cto.com/10730184/1774508【數據結構】經常使用排序算法(包括:選擇排序,堆排序,冒泡排序,選擇排序,快速排序,歸併排序)
算法
有興趣的話,相信聰明的你,一看就會秒懂快速排序的思想。數據結構
下面,咱們將快速排序優化:ide
一、三數取中來優化快速排序函數
優化緣由:優化
快速排序的擦差很少每次將序列一分爲二,時間複雜度是O(n*lgn).ui
咱們思考,快速排序的時間複雜度是O(n*lgn),在序列亂序時,它的效率很高。可是,當序列有序或者接近有序時,效率就沒有那麼高了。spa
若是一個序列是這樣的:blog
{10,5,1,4,5,9,6,1}
排序
咱們針對上述序列,若是要排成升序的話,咱們要找一個數知足挖坑法裏面的挪數據條件,或者說prev、cur法中的交換數據條件時,可能一直將序列從頭遍歷,找到結束或者快要結束才找到或者尚未找到,這時候至關於效率就變成了o(n^2)了。遞歸
優化方法:
所以,咱們想到了三數取中的思想。即序列的三個位置最左邊left,最右邊right,中間mid,三個數取出中間大小的數,用這個數作key.
三數取中的代碼以下:
int mid(int* a, int left, int right) { int mid = left - (left - right) / 2; if (a[left] < a[right]) { if (a[left] > a[mid]) { return a[left]; } else { if (a[right] < a[mid]) { return a[right]; } else { return a[mid]; } } } else { if (a[right] > a[mid]) { return a[right]; } else { if (a[left] < a[mid]) { return a[left]; } else { return a[mid]; } } } }
2.非遞歸的實現
優化緣由:
當一個序列較小時,每次將序列再成兩半,遞歸處理兩半的序列。
可是,當要給20萬、30萬這樣的序列排序時,每次遞歸的話,無疑每次調用函數創建棧幀會很很大的系統開銷,甚至會耗盡系統的空間。
優化方法:用棧stack模擬實現棧幀,每次壓棧出棧---》即遞歸寫法。
遞歸代碼以下:
int PartSort(int* a, int left, int right) { assert(a); int cur = left; int prev = cur - 1; int key = mid(a,left,right); swap(key, a[right]); while (cur < right) { if (a[cur] <= a[right]) { swap(a[++prev], a[cur]); } cur++; } swap(a[++prev], a[right]); return prev; } void QuickSort(int* a, int left, int right) { int prev = PartSort(a,left, right); if (prev - 1 > left) { QuickSort(a, left, prev - 1); } if (prev + 1 < right) { QuickSort(a, prev + 1, right); } }
非遞歸代碼以下(推薦):
//prev、cur法,也能夠採用挖坑法等其餘辦法 int PartSort(int* a, int left, int right) { assert(a); int cur = left; int prev = cur - 1; int key = mid(a,left,right); swap(key, a[right]);//將三數取中獲得的數據與a[right]處交換。 while (cur < right) { if (a[cur] <= a[right]) { swap(a[++prev], a[cur]); } cur++; } swap(a[++prev], a[right]); return prev; } void QuickSort_NonR(int* a, int left, int right) { stack<int> s; //左右區間壓入棧中,或者此時也能夠定義一個結構體,裏面有左右區間,一次把左右區間都壓進去 s.push(left); s.push(right); while (!s.empty()) { //[left,right] int curRight = s.top();//壓棧先壓的是左區間,先進後出,取數據先取右區間 s.pop(); int curLeft = s.top(); s.pop(); int prev = PartSort(a, curLeft, curRight);//將這個區間進行一次快速排序 if (prev - 1 > curLeft) { s.push(curLeft);//壓入新分的左端序列 s.push(prev - 1); } if (prev + 1 < curRight) { s.push(prev + 1);//壓入新分的右段區間 s.push(curRight); } } }