演算法導論學習筆記(一)快速排序及優化

2021-08-09 21:38:59 字數 1985 閱讀 3852

快排的偽**:

quick_sort(a,p,r)
初始呼叫傳入的引數是quick_sort(a,1,a.length)。

partition的偽**:

partition(a,p,r)
演算法維持幾個指標變數,p和r分別指向陣列的首尾元素,i為比基準元素x小的最後乙個元素,j為比基準元素大的最後乙個元素的下乙個。

也就是說,選取a[r]為基準元素(紫色),下標在[p,i]區間的元素(粉色部分)都小於等於基準元素x,下標在[i+1,j-1]區間的元素(綠色部分)都大於基準元素x,下標位於區間[j,r-1]的元素(白色部分)則是還沒有被排序的元素。

partition程式需要維持這樣幾個下標,使程式在執行時一直滿足上面的性質。

下面是乙個例子:

最壞情況劃分:最壞情況莫過於每次都產生的是0:(n-1)的劃分,此時演算法執行時間的遞迴式為:t(

n)=t

(n−1

)+t(

0)+θ

(n)=

t(n−

1)+θ

(n)

演算法的時間複雜度為θ(

n2) 。

最好情況劃分:最好情況就是每次劃分都產生兩個數量相等的子陣列,此時演算法執行時間的遞迴式為:t(

n)=2

t(n2

)+θ(

n)

演算法的時間複雜度為θ(

nlgn

) 隨機劃分:就算每次劃分都是1:9這樣看似什麼不平衡的劃分,最後的出來複雜度的結果仍然是θ(

nlgn

) ,只是係數相比最好情況要大一些;再比如最好情況和最壞情況交替出現,最終的結果仍然是θ(

nlgn

) 。

快速排序的最壞情況就是輸入的序列是有序的,如何對演算法進行改進,從而讓演算法複雜度並不依賴輸入資料呢?

答案是隨機選擇基準元素。在每次進行partitio過程中都先產生乙個隨機數,將這個隨機數所代表的元素與最後乙個元素交換從而完成隨機選擇基準元素,這樣演算法的複雜度完全跟隨機數的選取有關,而不是完全取決於輸入。

randomized_partition偽**如下:

randomized_partition(a,p,r)
新的快速排序就不需要呼叫partition,換成randomized_partition

randomized_quicksort(a,p,r)
並且可以證明這個演算法的期望執行時間為o(

nlgn

) 。

尾遞迴尾遞迴實際上是解決遞迴層次太深的問題,遞迴程式在執行時是使用棧來儲存遞迴資訊的,每遞迴一次就要將函式的引數,返回值等資訊壓入棧中儲存。這樣遞迴層次過深的話就會造成棧中資訊太多從而溢位的情況。為了避免出現這種情況,可以將程式改寫,在每次遞迴時,不需要儲存其他的資訊,只將本次遞迴的值儲存下來,再進行下一次遞迴,這樣可以有效的降低棧中儲存的資訊量,不用為每一次遞迴呼叫儲存狀態資訊,而只需要儲存正在執行的狀態資訊。

快速排序的尾遞迴優化其實很簡單,只有一行**:

tail_recursively_quicksort(a,p,r)
具體可以看看這篇文章快速排序的優化 和關於遞迴的問題,說說我的想法

三數取中劃分

所謂三數取中劃分就是在選取基準元素的時候,隨機選取三個數,然後取這三個數的中位數作為基準元素,看起來好像沒什麼影響,但其實從理論的角度分析會發現演算法的整體效能確實提公升了不少。

演算法導論7-5(三數取中劃分)

演算法導論7-4(快速排序中的堆疊深度)

演算法導論7-5(三數取中劃分)

演算法導論第七章最後思考題

演算法導論學習筆記(七) 快速排序

快速排序是乙個使用分治思想的排序演算法,具有如下優點 1.演算法的期望執行時間為 nlgn 且其中蘊含的常數因子較小,故而快速排序演算法通常是實際應用中最好的選擇。2.原址排序,排序過程中只需要有限個輔助空間。快速排序通過分治的演算法設計思想,借助關鍵子過程partition將輸入 這裡假定演算法的...

演算法導論之快速排序 學習筆記

或者你也可以打個比喻,想象一下,假設r為主元素,j元素為前方開路元素,和主元素進行比較,如果大於主元素則繼續開路 如果小於主元素則i元素加1之後和j元素交換之後,j元素繼續開路直到最後。書中給出了劃分的偽 1 partition a,p,r 2 x a r 將最後乙個元素作為主元素 3 i p 1 ...

學習演算法導論 快速排序

快速排序用的也是分治法,快速排序分為三個步驟 1.分解 陣列a low.high 被劃分為兩個 可能為空 的子陣列a low.q 1 和a q 1.high 使得a low.q 1 中的每個元素都小於等於a q 而a q 小於等於a q 1.high 中的每個元素。q是乙個劃分點。2.解決 通過遞迴...