快速排序和變種快排

2021-08-17 16:04:29 字數 3386 閱讀 2213

快速排序

假設我們現在要對乙個陣列ar進行排序。首先我們需要隨機選擇乙個基準值(一般選陣列的首元素),然後將陣列中的其他值與其進行比較,將小於它的數放在其左側,大於的放在右側(假定按從小到大排序)。這就完成了一趟快速排序

原始資料如下:

ar[0]

ar[1]

ar[2]

ar[3]

ar[4]

ar[5]

ar[6]

ar[7]

ar[8]

2245129

534103

27 ①.i=0; j=8; key=22;執行演算法思想中的第2步,從後向前找到第乙個小於key的值(ar[7]),此時i=0; j=7; key=22; 交換之後資料如下:

ar[0]

ar[1]

ar[2]

ar[3]

ar[4]

ar[5]

ar[6]

ar[7]

ar[8]345

129534

102227

②.i=0; j=7; key=22; 執行演算法思想中的第3步,從前向後找到第乙個大於key的值(ar[1]),此時i=1; j=7; key=22;交換之後資料如下:

ar[0]

ar[1]

ar[2]

ar[3]

ar[4]

ar[5]

ar[6]

ar[7]

ar[8]322

129534

104527

③.i=1; j=7; key=22; 執行演算法思想中的第2步,從後向前找到第乙個小於key的值(ar[6]),此時i=1; j=6; key=22;交換之後資料如下:

ar[0]

ar[1]

ar[2]

ar[3]

ar[4]

ar[5]

ar[6]

ar[7]

ar[8]310

129534

224527

④.i=1; j=6; key=22; 執行演算法思想中的第3步,從前向後找到第乙個大於key的值(ar[5]),此時i=5; j=6; key=22;交換之後資料如下:

ar[0]

ar[1]

ar[2]

ar[3]

ar[4]

ar[5]

ar[6]

ar[7]

ar[8]310

129522

344527

⑤.i=5; j=6; key=22; 執行演算法思想中的第2步,從後向前找到第乙個小於key的值,j–之後根據演算法思想中的第4步,i==j,結束第一趟快速排序。

⑥.此時陣列已經被分成了兩部分,小於key值的和大於key值的。在這兩部分中我們再取出每一部分的第乙個值作為key,再次進行上述步驟。

#include

using

namespace

std;

void quick_sort(int a,int left,int right)

a[i]=key;//當在陣列內找完一遍以後就把中間數key回歸

quick_sort(a,left,i-1);//一遍結束後資料就被分成了兩部分,這是對前一部分的quick_sort

quick_sort(a,i+1,right);//對後半部分的quick_sort

}void main()

; int n=sizeof(ar)/sizeof(int);

quick_sort(ar,0,n-1);

for(int i=0;icout

<" ";

cout

<隨機化快排

快速排序的最壞情況基於每次劃分對主元的選擇。基本的快速排序選取第乙個元素作為主元。這樣在陣列已經有序的情況下,每次劃分將得到最壞的結果。一種比較常見的優化方法是隨機化演算法,即隨機選取乙個元素作為主元。這種情況下雖然最壞情況仍然是o(n^2),但最壞情況不再依賴於輸入資料,而是由於隨機函式取值不佳。實際上,隨機化快速排序得到理論最壞情況的可能性僅為1/(2^n)。所以隨機化快速排序可以對於絕大多數輸入資料達到o(nlogn)的期望時間複雜度。一位前輩做出了乙個精闢的總結:「隨機化快速排序可以滿足乙個人一輩子的人品需求。」

隨機化快速排序的唯一缺點在於,一旦輸入資料中有很多的相同資料,隨機化的效果將直接減弱。對於極限情況,即對於n個相同的數排序,隨機化快速排序的時間複雜度將毫無疑問的降低到o(n^2)。解決方法是用一種方法進行掃瞄,使沒有交換的情況下主元保留在原位置。

平衡快排

每次盡可能地選擇乙個能夠代表中值的元素作為關鍵資料,然後遵循普通快排的原則進行比較、替換和遞迴。通常來說,選擇這個資料的方法是取開頭、結尾、中間3個資料,通過比較選出其中的中值。取這3個值的好處是在實際問題中,出現近似順序資料或逆序資料的概率較大,此時中間資料必然成為中值,而也是事實上的近似中值。萬一遇到正好中間大兩邊小(或反之)的資料,取的值都接近最值,那麼由於至少能將兩部分分開,實際效率也會有2倍左右的增加,而且利於將資料略微打亂,破壞退化的結構。

外部快排

與普通快排不同的是,關鍵資料是一段buffer,首先將之前和之後的m/2個元素讀入buffer並對該buffer中的這些元素進行排序,然後從被排序陣列的開頭(或者結尾)讀入下乙個元素,假如這個元素小於buffer中最小的元素,把它寫到最開頭的空位上;假如這個元素大於buffer中最大的元素,則寫到最後的空位上;否則把buffer中最大或者最小的元素寫入陣列,並把這個元素放在buffer裡。保持最大值低於這些關鍵資料,最小值高於這些關鍵資料,從而避免對已經有序的中間的資料進行重排。完成後,陣列的中間空位必然空出,把這個buffer寫入陣列中間空位。然後遞迴地對外部更小的部分,迴圈地對其他部分進行排序。

三路基數快排

(three-way radix quicksort,也稱作multikey quicksort、multi-key

quicksort):結合了基數排序(radix

sort,如一般的字串比較排序就是基數排序)和快排的特點,是字串排序中比較高效的演算法。該演算法被排序陣列的元素具有乙個特點,即multikey,如乙個字串,每個字母可以看作是乙個key。演算法每次在被排序陣列中任意選擇乙個元素作為關鍵資料,首先僅考慮這個元素的第乙個key(字母),然後把其他元素通過key的比較分成小於、等於、大於關鍵資料的三個部分。然後遞迴地基於這乙個key位置對「小於」和「大於」部分進行排序,基於下乙個key對「等於」部分進行排序。

演算法 快速排序 經典快排 隨機快排

經典快排的思路是選取陣列的最後乙個數 x,按照問題一的思路把整個陣列劃分成小於等於 x 大於 x兩個部分,將 x 和 大於 x 部分陣列的第乙個元素交換位置。此時整個陣列劃分成小於等於 x x 大於 x三個部分,也就是這一次排序將 x 值排好位置。再分別對小於等於 x和大於 x中的陣列遞迴劃分,直到...

快速排序(快排 遞迴實現)

時間複雜度 o nlogn 注意 1 時間複雜度與pivot的選取有關,最好能選到正中間 2 該排序不是穩定排序 1.0 不用swap函式 相較2.0節省時間 int qsort int l,int r s l pivot return l 2.0 用swap函式int qsort int l,in...

快速排序 快排 C語言

介紹 include 快速排序的函式 第乙個引數為要排序的陣列,第二個引數是參與排序的起始位置,第三個引數是引數排序的截止位置 void quicksort int arr int low,int height 找到陣列下標為第二個引數的值 在 公升序中應該在的 位置 下標 intfindpost ...