快速排序
與歸并排序一樣茶宵,快速排序也使用了分治的思想解決排序問題瓣窄。
對一個(gè)典型的子數(shù)組A[p..r]進(jìn)行快速排序的三步分治過程:
- 分解:數(shù)組A[p..r]被劃分為兩個(gè)(可能為空)子數(shù)組A[p..q-1]和A[q+1..r]匙瘪,使得A[p..q-1]中的每一個(gè)元素都小于等于A[q],而A[q]也小于等于A[q+1..r]中的每個(gè)元素厢呵。其中計(jì)算下標(biāo)q也算劃分過程的一部分窝撵。
- 解決: 通過遞歸調(diào)用快速排序,對子數(shù)組A[p..q-1]和A[q+1..r]進(jìn)行排序襟铭。
- 合并:因?yàn)樽訑?shù)組都是原址排序碌奉,所以不需要額外的合并操作:數(shù)組A[p..r]已經(jīng)有序。
偽代碼實(shí)現(xiàn)快速排序:
QUICKSORT(A,p,r)
if p < r
q=PARTITION(A,p,r)
QUICKSORT(A,p,q-1)
QUICKSORT(A,q+1,r)
Java實(shí)現(xiàn)版:
/**
*
* @param src 待排序的數(shù)組
*/
public static void quickSort(int[] src,int left ,int right){
if(left<right){
int mid=partition(src, left, right);
quickSort(src, left, mid-1);
quickSort(src, mid+1, right);
}
}
數(shù)組的劃分
算法的關(guān)鍵部分就是PARTITION過程寒砖,它實(shí)現(xiàn)了對子數(shù)組A[p..r]的原址重排赐劣。
PARTITION(A,p,r)
x=A[r]
i=p-1
for j=p to r-1
if A[j]<=x
i=i+1
exchange A[i] with A[j]
exchange A[i+1] with A[r]
return i+1
Java實(shí)現(xiàn)版:
/**
* 劃分操作
*
* @param src
* 待排序的數(shù)組
* @param left
* 左邊界
* @param right
* 右邊界
*/
public static int partition(int[] src, int left, int right) {
int key = src[left];//挖坑
int i = left;
int j = right;
while (i < j) {
while (i < j && src[j] > key) {
j--;
}
if (i < j) {
src[i++] = src[j];// 挖坑填數(shù)
}
while (i < j && src[i] < key) {
i++;
}
if (i < j) {
src[j--] = src[i];// 挖坑填數(shù)
}
}
src[i] = key;//填空
// 這種情況下第一趟結(jié)束 i的坐標(biāo)都比他小i的右邊都比他大
return i;
}
隨機(jī)化版本的快速排序
在理解了快速排序的劃分過程之后,隨機(jī)化快速排序的過程就很好理解了哩都。
首先隨機(jī)化快排是為了解決出現(xiàn)最壞情況時(shí) Ω(n^2)的運(yùn)行時(shí)間的問題魁兼,將快速排序變成一個(gè)“穩(wěn)定”的算法,隨機(jī)化后漠嵌,快排的期望運(yùn)行時(shí)間為O(n* lg n)咐汞。
隨機(jī)化快排其實(shí)做的很簡單,就是在劃分的時(shí)候儒鹿,不是確定性的選擇主元(provit)化撕,而是隨機(jī)的選擇主元,這要就保證了只有很小的幾率下每次都出現(xiàn)最壞的劃分情況挺身。
隨機(jī)化快排的劃分過程:
/**
* 隨機(jī)劃分操作
*
* @param src
* 待排序的數(shù)組
* @param left
* 左邊界
* @param right
* 右邊界
*/
public static int randomizedPartition(int[] src, int left, int right) {
/*隨機(jī)選取主元元素*/
Random random = new Random();
int random_index = random.nextInt(right-left+1)+left;
System.out.println("random_index="+random_index);
/**
* 交換
*/
int temp = src[random_index];
src[random_index] = src[left];
src[left]=temp;
int key = src[left];//挖坑
int i = left;
int j = right;
while (i < j) {
while (i < j && src[j] > key) {
j--;
}
if (i < j) {
src[i++] = src[j];// 挖坑填數(shù)
}
while (i < j && src[i] < key) {
i++;
}
if (i < j) {
src[j--] = src[i];// 挖坑填數(shù)
}
}
src[i] = key;//填空
// 這種情況下一趟結(jié)束 i的坐標(biāo)都比他小i的右邊都比他大
return i;
}
以上侯谁,謝謝閱讀,希望你有所收獲章钾!
算法導(dǎo)論公開課筆記(一)算法分析與設(shè)計(jì)
算法導(dǎo)論公開課筆記(二)快速排序和隨機(jī)化算法
算法導(dǎo)論公開課筆記(三)線性時(shí)間排序
算法導(dǎo)論公開課筆記(四)順序統(tǒng)計(jì)墙贱、中值
動(dòng)態(tài)規(guī)劃算法