寫在前面的話
最近系統地學習了快速排序演算法,在此作一筆記。主要包括快排的各種版本:普通版本,改進的普通版本,隨機化版本,三數值取中分割版本和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,...