【46期】盤點那些必問的數(shù)據(jù)結(jié)構(gòu)算法題之快速排序
閱讀本文大概需要 5 分鐘。
來自:juejin.im/post/5bae28e35188255c6f1e2bb1
0 概述
劃分:數(shù)組 A[p…r] 被劃分為兩個子數(shù)組 A[p…q-1] 和 A[q+1…r],使得 A[p…q-1] 中每個元素都小于等于 A[q],而 A[q+1…r] 每個元素都大于 A[q]。劃分流程見下圖。
解決:通過遞歸調(diào)用快速排序,對子數(shù)組分別排序即可。
合并:因為兩個子數(shù)組都已經(jīng)排好序了,且已經(jīng)有大小關(guān)系了,不需要做任何操作。

https://github.com/shishujuan/dsalg/tree/master/code/alg/sort
1 樸素的快速排序
/**
?*?快速排序-樸素版本
?*/
void?quickSort(int?a[],?int?l,?int?u)
{
????if?(l?>=?u)?return;
????int?q?=?partition(a,?l,?u);
????quickSort(a,?l,?q-1);
????quickSort(a,?q+1,?u);
}
/**
?*?快速排序-劃分函數(shù)
?*/
int?partition(int?a[],?int?l,?int?u)
{
????int?i,?q=l;
????for?(i?=?l+1;?i?<=?u;?i++)?{
????????if?(a[i]?????????????swapInt(a,?i,?++q);
????}
????swapInt(a,?l,?q);
????return?q;
}
2 改進-雙向劃分的快速排序
/**
?*?快速排序-雙向劃分函數(shù)
?*/
int?partitionLR(int?a[],?int?l,?int?u,?int?pivot)
{
????int?i?=?l;
????int?j?=?u+1;
????while?(1)?{
????????do?{
????????????i++;
????????}?while?(a[i]?//注意i<=u這個判斷條件,不能越界。
????????do?{
????????????j--;
????????}?while?(a[j]?>?pivot);
????????if?(i?>?j)?break;
????????swapInt(a,?i,?j);
????}
????//?注意這里是交換l和j,而不是l和i,因為i與j交叉后,a[i...u]都大于等于樞紐元t,
????//?而樞紐元又在最左邊,所以不能與i交換。只能與j交換。
????swapInt(a,?l,?j);
????return?j;
}
/**
?*?快速排序-雙向劃分法
?*/
void?quickSortLR(int?a[],?int?l,?int?u)
{
????if?(l?>=?u)?return;
????int?pivot?=?a[l];
????int?q?=?partitionLR(a,?l,?u,?pivot);
????quickSortLR(a,?l,?q-1);
????quickSortLR(a,?q+1,?u);
}
3 繼續(xù)改進—隨機法和三數(shù)取中法取樞紐元
/**
?*?隨機選擇樞紐元
?*/
int?pivotRandom(int?a[],?int?l,?int?u)
{
????int?rand?=?randInt(l,?u);
????swapInt(a,?l,?rand);?//?交換樞紐元到位置l
????return?a[l];
}
/**
?*?三數(shù)取中選擇樞紐元
?*/
int?pivotMedian3(int?a[],?int?l,?int?u)
{
?????int?m?=?l?+?(u-l)/2;
?????/*
??????*?三數(shù)排序
??????*/
?????if(?a[l]?>?a[m]?)
????????swapInt(a,?l,?m);
?????if(?a[l]?>?a[u]?)
????????swapInt(a,?l,?u);
?????if(?a[m]?>?a[u]?)
????????swapInt(a,?m,?u);
?????/*?assert:?a[l]?<=?a[m]?<=?a[u]?*/
?????swapInt(a,?m,?l);?//?交換樞紐元到位置l
?????return?a[l];
}
4 非遞歸寫快速排序
/**
?*?快速排序-非遞歸版本
?*/
void?quickSortIter(int?a[],?int?n)
{
????Stack?*stack?=?stackNew(n);
????int?l?=?0,?u?=?n-1;
????int?p?=?partition(a,?l,?u);
????if?(p-1?>?l)?{?//左半部分兩個邊界值入棧
????????push(stack,?p-1);?
????????push(stack,?l);
????}
????if?(p+1?//右半部分兩個邊界值入棧
????????push(stack,?u);
????????push(stack,?p+1);
????}
????while?(!IS_EMPTY(stack))?{?//棧不為空,則循環(huán)劃分過程
????????l?=?pop(stack);
????????u?=?pop(stack);
????????p?=?partition(a,?l,?u);
????????if?(p-1?>?l)?{
????????????push(stack,?p-1);
????????????push(stack,?l);
????????}
????????if?(p+1?????????????push(stack,?u);
????????????push(stack,?p+1);
????????}
????}
}
推薦閱讀:
【45期】盤點那些必問的數(shù)據(jù)結(jié)構(gòu)算法題之基礎(chǔ)排序
【44期】盤點那些必問的數(shù)據(jù)結(jié)構(gòu)算法題之二分查找算法
【43期】盤點那些必問的數(shù)據(jù)結(jié)構(gòu)算法題之二叉樹基礎(chǔ)
微信掃描二維碼,關(guān)注我的公眾號
朕已閱?
評論
圖片
表情

