適用於待排序列為部分有序時,固定選樞軸導致效率低下。
/*隨機選擇樞軸的位置,區間在low和high之間*/
intselectpivotrandom
(int arr,
int low,
int high)
總結:這是一種相對安全的策略。由於樞軸的位置是隨機的,那麼產生的分割也不會總是會出現劣質的分割。在整個陣列數字全相等時,仍然是最壞情況,時間複雜度是o(n ^ 2)。實際上,隨機化快速排序得到理論最壞情況的可能性僅為1/(2^n)。所以隨機化快速排序可以對於絕大多數輸入資料達到o(nlogn)的期望時間複雜度。但是無法具有大量重複資料的序列。
/*函式作用:取待排序序列中low、mid、high三個位置上資料,選取他們中間的那個資料作為樞軸*/
intselectpivotmedianofthree
(int arr,
int low,
int high)
if(arr[low]
> arr[high]
)//目標: arr[low] <= arr[high]
if(arr[mid]
> arr[low]
)//目標: arr[low] >= arr[mid]
//此時,arr[mid] <= arr[low] <= arr[high]
return arr[low]
;//low的位置上儲存這三個位置中間的值
//分割時可以直接使用low位置的元素作為樞軸,而不用改變分割函式了
}
優化1、當待排序序列的長度分割到一定大小後,使用插入排序。原因:對於很小和部分有序的陣列,快排不如插排好。當待排序序列的長度分割到一定大小後,繼續分割的效率比插入排序要差,此時可以使用插排而不是快排
if
(high - low +
1<10)
//else時,正常執行快排
優化2、在一次分割結束後,可以把與key相等的元素聚在一起,繼續下次分割時,不用再對與key相等元素分割(解決序列中含有大量重複資料)
具體過程:
第一步,在劃分過程中,把與key相等元素放入陣列的兩端
第二步,劃分結束後,把與key相等的元素移到樞軸周圍
舉例:待排序序列
1 4 6 7 6 6 7 6 8 6三數取中選取樞軸:下標為4的數6
轉換後,待分割序列:
6 4 6 7 1 6 7 6 8 6樞軸key:6
第一步,在劃分過程中,把與key相等元素放入陣列的兩端
結果為:
6 4 1 6(樞軸) 7 8 7 6 6 6此時,與6相等的元素全放入在兩端了
第二步,劃分結束後,把與key相等的元素移到樞軸周圍
結果為:
1 4 66(樞軸) 6 6 6 7 8 7
void
qsort
(int arr,
int low,
int high)
//一次分割
int key =
selectpivotmedianofthree
(arr,low,high)
;//使用三數取中法選擇樞軸
while
(low < high)
high--;}
arr[low]
= arr[high]
;while
(high > low && arr[low]
<= key)
low++;}
arr[high]
= arr[low];}
arr[low]
= key;
//一次快排結束
//把與樞軸key相同的元素移到樞軸最終位置周圍
利用荷蘭國旗問題改進經典快排和隨機快排
每次取陣列中最後乙個值,依照這個值把陣列分為兩份,小於的在左邊,大於的在右邊。再依次按照這樣的思想進行操作。ps 荷蘭國旗問題可以看另一篇部落格 荷蘭國旗問題把陣列是分為三個部分的,小於 等於 大於這三個部分。按照這樣的思想,等於部分就不需要進行再次進行排序,這樣就能減少很大一部分的開銷。改進之後的...
快排2 經典快排和荷蘭國旗快排
基礎知識見 建議先閱讀基礎知識,並自己手推一遍 演算法原理 第一步 取陣列最後乙個數作為num,將陣列中的 num的數放在陣列的左邊,num的數放在陣列的右邊,這是可以理解為分成了兩個陣列 第二步 然後將 num的部分當成乙個陣列,繼續第一步 num的部分同理 第三步 若陣列的大小 2,則結束。流程...
演算法導論 改進快排(3) 棧深度 習題7 4
問題 快排演算法包含了兩個對自身的遞迴呼叫,每次遞迴呼叫的資訊存入棧中,作業系統給程式的棧空間是有限的,如果陣列很大,則很容易造成棧溢位,這樣程式就崩潰了。思路 quicksort中的第二個遞迴用乙個迴圈控制結構來代替 尾遞迴 實現 include include includeusing name...