演算法導論 快速排序

2021-09-26 04:49:11 字數 2191 閱讀 9583

什麼是排序?

考慮對於給定輸入的某乙個陣列 a

=a = \

a=, 經過排序演算法,我們可以得到原始排列的乙個序列a

=a=\, a_2^,..., a_n^\}

a=, 其中asi′+1

′a_ si^ < a_^

as​i

′+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上也刷到過,而且對於陣列的快排,真是從大學到研究生一直都要求必須掌握的重點知識,然而自己不斷的思考,卻發現所謂的快排,比我以前想象的要複雜的多,因為快排的思想非常幹練,但是形式,或者說具體實現千變萬化,為了達到萬變不離其宗,筆...