演算法|快速排序
阿新 • • 發佈:2021-07-06
完成閱讀您將會了解快速排序的:
- 演算法思想
- 實現步驟
- 實踐範例(C++/Rust)
1. 演算法思想
快速排序(Quick Sort),簡稱快排,最早由 C.A.R.Hoare 在1962年於快速排序[1]一文提出。快速排序實質上運用分治(Divide & Conquer)思想,每次選取基準元素(Pivot Element),並將剩餘元素在其左右分為小於與不小於基準元素的兩個子序列(Sub-sequence),然後針對子序列遞迴地進行快速排序,如圖1[2]。
快速排序為不穩定排序(Unstable Sort),即同值元素排序後未必保持原有相對位置,如圖2-3[3]。快速排序時間複雜度為\(O(n^2)\)
2. 實現步驟
- 選擇基準元素;(序列尾,本文程式範例中隨機選取基準)
- 將不小於和不大於基準元素的元素分割槽為左右兩個子序列,與此同時基準元素本身已完成排序,如圖4[3:1];
- 遞迴排序子序列。
3. 實踐範例(C++/Rust)
問題描述:
為無序陣列A做單調不減排序。
輸入
輸出:有序陣列A
解答思路:
運用快速排序演算法對A進行原址排序。
虛擬碼1:分割槽
變數說明:A\(\rightarrow\)待排序陣列;l\(\rightarrow\)子序列左閉邊界;r\(\rightarrow\)子序列右閉邊界;p\(\rightarrow\)分割槽點;iter\(\rightarrow\)迭代替量
虛擬碼2
變數說明:A\(\rightarrow\)待排序陣列;l\(\rightarrow\)子序列左閉邊界;r\(\rightarrow\)子序列右閉邊界;p\(\rightarrow\)分割槽點 \[\begin{aligned} &QUICKSORT(A,l,r) \\ &~~~~~~ if~~~l<r \\ &~~~~~~~~~~~~p \leftarrow PARTITION(A,l,r) \\ &~~~~~~~~~~~~QUICKSORT(A,l,p-1) \\ &~~~~~~~~~~~~QUICKSORT(A,p+1,r) \\ \end{aligned} \]
C++解答:傳指標入參
constexpr auto _partition(auto l, auto r) noexcept {
auto p = l, iter = p - 1;
auto pivot = *r;
while (++iter < r)
if (*iter < pivot)
std::swap(*iter, *p++);
std::swap(*p, *r);
return p;
}
void quick_sort(auto l, auto r) noexcept {
srand(time(nullptr));
if (l < r) {
std::swap(*(l + rand() % (r - l + 1)), *r);
auto p = _partition(l, r);
quick_sort(l, p - 1);
quick_sort(p + 1, r);
}
}
Rust解答:
fn _partition<T: Clone + std::cmp::PartialOrd>(A: &mut Vec<T>, l: usize, r: usize) -> usize {
let (mut p, pivot) = (l, A[r].clone());
for i in l..r {
if A[i] < pivot {
A.swap(i, p);
p += 1;
}
}
A.swap(p, r);
p
}
pub fn quick_sort<T: Clone + std::cmp::PartialOrd>(A: &mut Vec<T>, l: usize, r: usize) {
if l < r {
A.swap(thread_rng().gen_range(l..=r), r);
let mut p = _partition(A, l, r);
quick_sort(A, l, p - 1);
quick_sort(A, p + 1, r);
}
}
4. 自我測試
虛擬碼實踐:
快排遞迴版受棧記憶體限制,無法直接應用在大規模資料上,請將快排改寫成迭代版。
LeetCode選薦:
讓每一天足夠精緻,期待與您的再次相遇! ^_^