對於快排的改進

2021-09-26 02:23:27 字數 2492 閱讀 6740

適用於待排序列為部分有序時,固定選樞軸導致效率低下。

/*隨機選擇樞軸的位置,區間在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...