abstract
本文是對快速排序算法的深入分析,主要講解了快速排序算法的基本原理,時間複雜度分析以及如何去改進的快排算法,本文提供快排的僞代碼,以及用Golang實現的具體代碼。
這裏補充一下一般算法設計的思路,首先根據問題分析建模,設計最初版本的代碼,分析代碼的running time,然後找到問題所在,解決問題。這樣的。
the idea of algorithm
快速排序算法是典型的使用分治法設計的算法,算法主要分爲:
divide:key這是快排的關鍵,
conquer:recursive sort 2 part
combine:這部分不做什麼,因爲快排不像merge sort沒有消耗而外的空間
實現快排的關鍵就是在線性的時間,完成對子數組的分割
common quick sorting
我們先開快排的僞代碼
//其中分割函數
partition(A, p, q)
X <- A[p]
curr <- p
for j <- p+1 to q
do if A[j] <= X
then curr <- curr+1
exch A[curr] A[j]
exch A[p] A[curr]
return curr
//對於combine部分
quickSort(A, p, q)
if p < q then
mid <- partion(A, p, q)
quickSort(A, p, mid-1)
quickSort(A, mid+1, q)
使用GO實現的代碼如圖所示:
func partition(A []int, left, right int) int{
midNum := A[left]
startFLag := left
for i := left+1; i <=right; i++{
if A[i] <= midNum{
startFLag++
A[i], A[startFLag] = A[startFLag], A[i]
}
}
A[left], A[startFLag] = A[startFLag], A[left]
return startFLag
}
func QuickSort(A []int, left
- [ ] List item
, right int) {
if right > left{
mid := partition(A, left, right)
QuickSort(A, left, mid-1)
QuickSort(A, mid+1, right)
}
}
下面說一下時間複雜度
上述算法的運行時間是取決於輸入數據的情況。
我們來考慮==最好的情況(卵用沒有)==假設每次選擇的數據都會置換到當前數據段的中心,那遞歸公式爲 所以其running time爲
我們考慮最壞的情況,每次置換過後的位置都是,那遞歸公式就是所以其running time爲
對於一個普通的情況,一般會偏向於好的情況一點,但是這種程度的算法是達不到實際使用需求的。
rand quick sorting
考慮到上面的問題,我們需要改進快速排序算法,其中最容易想到的是:將挑選的元素隨機話。
func randPartition(A []int, left, right int) int{
key := int(rand.Int63n(int64(right-left))) + left
A[left], A[key] = A[key], A[left]
midNum := A[left]
startFLag := left
for i := left+1; i <=right; i++{
if A[i] <= midNum{
startFLag++
A[i], A[startFLag] = A[startFLag], A[i]
}
}
A[left], A[startFLag] = A[startFLag], A[left]
return startFLag
}
其中隨機話處理的代碼如上所示。這樣處理能夠帶來什麼樣的好處了。這樣能保證算法的
下面是純數學分析,如果不想了解太深,完全沒有必要看
在證明上面的結論上,需要使用到一個定律
首先定義了一個這樣的概率分佈函數
對於T(n)這個函數,它的表現形式就可以寫成式中可以不考慮k=0和1的情況。
根據獨立分佈的特性可以推導爲
即
再用代換法加上上面給出的定理來證明:
假設
so when , the next is proved