快速排序演算法的幾種版本及實現

2021-06-01 19:07:12 字數 3234 閱讀 8388

寫在前面的話

最近系統地學習了快速排序演算法,在此作一筆記。主要包括快排的各種版本:普通版本,改進的普通版本,隨機化版本,三數值取中分割版本和stooge版本。對各版本進行了簡要分析,並給出了具體實現。

《演算法導論》對快排的描述

快速排序是基於分治模式的,下面是對乙個典型子陣列a[p..r]排序的分治過程的三個步驟:

分解:陣列a[p..r]被劃分成兩個(可能空)子陣列a[p..q-1]和a[q+1..r],使得a[p..q-1]中的每個元素都小於等於a(q),而且,小於等於a[q+1..r]中的元素。下標q也在這個劃分過程中計算。

解決:通過遞迴呼叫快速

排序,對子陣列a[p..q-1]和a[q+1..r]排序。

合併:因為兩個子陣列是就地排序的,它們的合併不需要操作:整個陣列a[p..r]已排序

快速排序的關鍵是partition(分解)過程,它對子陣列a[p..r]進行就地重排。partition結果的好壞直接影響快排的效率。

下面用具體**來分析各種版本的快排。首先是《演算法導論》7.1節描述的,普通版的快排。

#include

"stdio.h" /*

普通版快速排序*/

//函式宣告

void

quicksort(int a,int n);

void

qsort(int a,int l, int r);

intpartition(int a,int l, int r);

intpartition(int a,int p, int r) //

分割過程 }

t = a[i+1]; a[i+1] = a[r]; a[r] = t;

return i+1; }

void

qsort(int a,int l, int r) //

三個引數的快排子模組 }

void

quicksort(int a,int n)   //快排

void

main()    //

驗證排序;

quicksort(a, 5);

for(int i=0;i<5;i++)

printf("\n");

} 這個版本的partition方法簡單易懂,但有時會有一些不必要的交換發生,如排序2 8 1 3 5 6 4

2 8 1 3 5 6 4

第一次交換8和1

2 1 8 3 5 6 4

第二次交換8和3

2 1 3 8 5 6 4

最後一次交換8和4

2 1 3 4 5 6 8

一次分割完成

對partition過程稍加修改,得到優化的分解過程:

intpartition(

inta,

intl,

intr) 

//稍加優化的分割過程

else

break;}

t = a[i]; a[i] = a[r]; a[r] = t;

returni;}

這一partition過程通過比較,減少了交換次數。

上面兩種方法都把輸入陣列的最後乙個元素作為主元,即哨兵元素。

如果輸入是隨機的,那麼這是可以接受的,但是如果輸入是預排序的或是反序的,那麼這樣的主元就產生乙個劣質的分割,因為所有元素不是都被劃入a[p..q-1]就是都被劃入a[q+1..r]。

下面給出兩種可以避免產生劣質分割的partition過程。

/*隨機分割法*/

intpartition(

inta,

intp,

intr)

else

break;}

t = a[i]; a[i] = a[r]; a[r] = t;

returni;}

/*三數值取中分割法*/

intpartition(

inta,

intp,

intr)

if(a[p] > a[r])

if(a[c] > a[r])

/*使得a[l] <= a[c] <= a[r] */

intk = r - 1;

t = a[c]; a[c] = a[k]; a[k] = t; 

/*將主元放在r-1的位置*/

intx = a[k];

inti = p-1, j = k;

while

(1)else

break;}

t = a[i]; a[i] = a[k]; a[k] = t;

returni;}

<

/*stooge_sort stooge

排序*/

void

stooge(

inta,

inti,

intj)

if(i+1 >= j)

return

;int

k = (j-i+1)/3;

// first 2/3

stooge(a, i, j-k);

// last 2/3

stooge(a, i+k, j);

// first 2/3

stooge(a, i, j-k);

}int

partition(

inta,

intp,

intr)

}int

temp = a[i+1];

a[i+1] = a[r];

a[r] = temp;

return

i+1;

}int

main()

;for

(int

i=0;i<8;i++)

printf(

"%d "

,a[i]);

printf(

"\n"

);int

x = partition(a, 0, 3);

intlen =

sizeof

(a)/

sizeof

(int

);stooge(a, 0, len-1);

for(

inti=0;i<8;i++)

printf(

"%d "

,a[i]);

printf(

"\n"

);return0;}

/p> 

stooge排序簡單易懂,但遺憾的是其效率很低,因為遞迴和比較的次數太多。

快速排序演算法的幾種實現

序列範圍 l,u 選取第乙個元素為樞紐值,然後圍繞t劃分陣列 m a 1 for i a,b if x i 迴圈終止後有 此時交換x l 和x m 即可。void qsort1 int x,int l,int u swap x l x m qsort x,l,m 1 qsort x,m 1,u 可以...

幾種快速的排序演算法

鴿巢排序,排序位元組串 寬位元組串最快的排序演算法,計數排序的變種 將計數緩衝區大小固定,少一次遍歷開銷 速度是stl中std sort的20多倍 更重要的是實現極其簡單!缺點是需要乙個size至少等於待排序陣列取值範圍的緩衝區,不適合int等大範圍資料。多一次遍歷的計數排序,排序位元組串的話速度約...

幾種常見的排序演算法及實現(一)

1 選擇排序 基本原理 對於給定的一組記錄,經過第一輪比較後得到最小的記錄,然後將該記錄與第乙個記錄的位置進行交換 接著對不包含第乙個記錄以外的其他記錄進行第二輪比較,得到最小的記錄並與第二個記錄進行位置交換 重複該過程,直到進行比較的記錄只有乙個時為止。void selectsort int a,...