什麼是排序?
考慮對於給定輸入的某乙個陣列 a
=a = \
a=, 經過排序演算法,我們可以得到原始排列的乙個序列a
=a=\, a_2^,..., a_n^\}
a=, 其中asi′+1
′a_ si^ < a_^
asi
′+1′
.什麼是快速排序?
快速排序基於分治的思想:
分解:陣列 a[p, …, r] 被劃分為兩個子陣列(子陣列可以為空),分別是 a[p,…, q-1] 和 a[ q + 1,…, r], 使得 a[p,…, q-1] 中每個元素都小於等於 a[q], a[ q + 1,…, r] 中每個元素都大於等於 a[q], 其中下標 q 的選擇也是劃分過程的一部分。
解決:遞迴呼叫快速排序,對 a[p,…, q-1] 和 a[ q + 1,…, r]進行排序。
合併:因為子陣列是原址排序,因此不需要合併。
快速排序分為兩部分:排序部分(主體)和劃分部分。
首先來看劃分部分:它是快排演算法的關鍵,它實現了子陣列 a[p, …, r] 的原址重排序,其過程如下圖例所示,以a = [2,8,7,1,3,5,6,4] 為例:
劃分部分(partition 部分)的**為:
int partition( vector& a, int p, int r)
swap(a[i+1], a[r]);
return i + 1;
}下面來看快速排序的主體部分:
void quicksort( vector& a, int p, int r)
}
注:該** ac 了 leetcode 912題。因此這裡不再給出測試用例。
演算法分析:**分為兩部分:
partition 操作於行時間為o(n
)o(n)
o(n)
.主體部分依靠partition操作。最壞結果:當劃分結果十分不平衡時(兩個子陣列的長度分別為 0 和 n - 1時),有t(n
)=t(
n−1)
+o(n
)=o(
n2)t(n) = t(n-1) + o(n) = o(n^2)
t(n)=t
(n−1
)+o(
n)=o
(n2)
. 最好結果:當劃分結果平衡(兩個子陣列長度均為n/2),有t(n
)=t(
n−1)
+o(n
)=o(
n2)=
o(nl
ogn)
t(n) = t(n-1) + o(n) = o(n^2) = o(nlogn)
t(n)=t
(n−1
)+o(
n)=o
(n2)
=o(n
logn
).對於平均排序,我們更加關注平均執行時間,事實證明,快速排序的平均執行時間更加趨向於最好情況,即快排的平均執行時間為o(n
logn
)o(nlogn)
o(nlog
n).為證明上述情況,假設劃分的比例為 9:1, 可得遞迴式為t(n
)=t(
9n/10
)+t(
n/10)
+o(n
)t(n) =t(9n/10) + t(n/10) + o(n)
t(n)=t
(9n/
10)+
t(n/
10)+
o(n)
, 由遞迴樹分析可知,t(n
)=o(
nlog
n)t(n) = o(nlogn)
t(n)=o
(nlo
gn).
事實上,即使劃分的比例為 99:1, 快排的平均時間依舊如此(通俗而言,任何一種常數比例的劃分,快排的執行時間不會發生變化)。
為了使快速排序演算法效能更優,主元元素可以隨機選擇。
當陣列元素均不相同,且逆序排列時,快排效能最糟糕。
快速排序 演算法導論
對於包含n個數的輸入陣列來說,快速排序是一種最壞情況時間複雜度為o n 的排序演算法。雖然最壞情況時間的複雜度很差,但是快速排序通常是實際排序應用中最好的選擇,因為它的平均效能非常好 它的期望時間複雜度是o nlgn 而且o nlgn 中隱含的常數因子非常小,另外,它還能夠進行原址排序,甚至在虛存環...
演算法導論 快速排序
既然敢叫 快速排序 必然有其過人之處。事實上,它確實是最快的通用內部排序演算法。它由hoare於1962年提出,相對歸併排序來說不僅速度快,並且不需要輔助空間。對於包含n個數的輸入陣列來說,快速排序是一種最壞情況時間複雜度為o n 2 的排序演算法。雖然最壞情況時間複雜度差,但是快速排序通常是實際排...
《演算法導論》 快速排序
最近和朋友聊天,聊到企業面試時考了一道鍊錶的快排,這道題在leetcode上也刷到過,而且對於陣列的快排,真是從大學到研究生一直都要求必須掌握的重點知識,然而自己不斷的思考,卻發現所謂的快排,比我以前想象的要複雜的多,因為快排的思想非常幹練,但是形式,或者說具體實現千變萬化,為了達到萬變不離其宗,筆...