快速排序的幾種改進

2021-05-27 23:36:10 字數 2593 閱讀 4797

快速排序,顧名思義,快速排序的速度是很快的,平均複雜度是nlogn。

快速排序的思路:

1.分治的思想,把陣列分成兩份,兩份分成4分,這樣分到足夠小,就能很好排序咯,然後把他們合起來,排序完成。

2.該分治思想和合併排序思想一樣,但是處理上更搞一籌,他是把小的和大的分成兩份,這樣在最後合併的時候,就不會像合併排序那樣還要檢查,因為本來就是左邊比右邊小,所以可以做到原地排序(就是不用申請多餘的空間)。

3.如何做好把小和大的分開時關鍵,我們做的就是以乙個數字基準,然後找到這個數的位置。把比他小的放在他的左邊,比他大的放在他的右邊,這樣不就分開了嘛。

快速排序已經很快了,但是還有改進的餘地:

1. 三平均分割槽法[1][9]

關於這一改進的最簡單的描述大概是這樣的:與一般的快速排序方法不同,它並不是選擇待排陣列的第乙個數作為中軸,而是選用待排陣列最左邊、最右邊和最中間的三個元素的中間值作為中軸。這一改進對於原來的快速排序演算法來說,主要有兩點優勢[1]:

(1) 

首先,它使得最壞情況發生的機率減小了。

(2) 

其次,未改進的快速排序演算法為了防止比較時陣列越界,在最後要設定乙個哨點。如果在分割槽排序時,中間的這個元素(也即中軸)是與最右邊數過來第二個元素進行交換的話,那麼就可以省略與這一哨點值的比較。

關於這一改進還有不同的說法,或者說關於這一改進還有更進一步的改進,在繼續的改進中不僅僅是為了選擇更好的中軸才進行左中右三個元素的的比較,它同時將這三個數排好序後按照其順序放回待排陣列,這樣就能夠保證乙個長度為n的待排陣列在分割槽之後最長的子分割槽的長度為n-2,而不是原來的n-1。通過這一技巧,能使得演算法的執行時間減少5%左右[9]。

對於三平均分割槽法還可以進一步擴充套件,在選取中軸值時,可以從由左中右三個中選取擴大到五個元素中或者更多元素中選取,一般的,會有(2t+1)平均分割槽法(median-of-(2t+1),三平均分割槽法英文為median-of-three)。在 

[9]中有對(2t+1)平均分割槽法改進的詳細分析,不過文章比較長,讀起來也比較困難,所以我就看了個開頭。裡面對三平均分割槽法也做了詳細的分析,並做出了理論的乙個估算,其平均複雜度為,小於上面所說的一般的快速排序演算法的平均複雜度 

[9]。

2. 根據分割槽大小調整演算法[7][8]

這一方面的改進是針對快速排序演算法的弱點進行的。快速排序對於小規模的資料集效能不是很好。可能有人認為可以忽略這個缺點不計,因為大多數排序都只要考慮大規模的適應性就行了。但是快速排序演算法使用了分治技術,最終來說大的資料集都要分為小的資料集來進行處理。由此可以得到的改進就是,當資料集較小時,不必繼續遞迴呼叫快速排序演算法,而改為呼叫其他的對於小規模資料集處理能力較強的排序演算法來完成。[7] 

introsort就是這樣的一種演算法,它開始採用快速排序演算法進行排序,當遞迴達到一定深度時就改為堆排序來處理。這樣就克服了快速排序在小規模資料集處理中複雜的中軸選擇,也確保了堆排序在最壞情況下o(n 

log 

n)的複雜度。[8]

另一種優化改進是當分割槽的規模達到一定小時,便停止快速排序演算法。也即快速排序演算法的最終產物是乙個「幾乎」排序完成的有序數列。數列中有部分元素並沒有排到最終的有序序列的位置上,但是這種元素並不多。可以對這種「幾乎」完成排序的數列使用插入排序演算法進行排序以最終完成整個排序過程。因為插入排序對於這種「幾乎」完成的排序數列有著接近線性的複雜度。這一改進被證明比持續使用快速排序演算法要有效的多。

另一種快速排序的改進策略是在遞迴排序子分割槽的時候,總是選擇優先排序那個最小的分割槽。這個選擇能夠更加有效的利用儲存空間從而從整體上加速演算法的執行。[7]

3. 不同的分割槽方案考慮[8]

對於快速排序演算法來說,實際上大量的時間都消耗在了分割槽上面,因此乙個好的分割槽實現是非常重要的。尤其是當要分割槽的所有的元素值都相等是,一般的快速排序演算法就陷入了最壞的一種情況,也即反覆的交換相同的元素並返回最差的中軸值。無論是任何資料集,只要它們中包含了很多相同的元素的話,這都是乙個嚴重的問題,因為許多「底層」的分割槽都會變得完全一樣。

對於這種情況的一種改進辦法就是將分割槽分為三塊而不是原來的兩塊:一塊是小於中軸值的所有元素,一塊是等於中軸值的所有元素,另一塊是大於中軸值的所有元素。另一種簡單的改進方法是,當分割槽完成後,如果發現最左和最右兩個元素值相等的話就避免遞迴呼叫而採用其他的排序演算法來完成。

4. 並行的快速排序[4][6]

由於快速排序演算法是採用分治技術來進行實現的,這就使得它很容易能夠在多台處理機上並行處理。

在大多數情況下,建立乙個執行緒所需要的時間要遠遠大於兩個元素比較和交換的時間,因此,快速排序的並行演算法不可能為每個分割槽都建立乙個新的執行緒。一般來說,會在實現**中設定乙個閥值,如果分割槽的元素數目多於該閥值的話,就建立乙個新的執行緒來處理這個分割槽的排序,否則的話就進行遞迴呼叫來排序。[4] 

[6]對於這一並行快速排序演算法也有其改進。該演算法的主要問題在於,分割槽的這一步驟總是要在子串行並行處理之前完成,這就限制了整個演算法的並行程度。解決方法就是將分割槽這一步驟也並行處理。改進後的並行快速排序演算法使用2n個指標來並行處理分割槽這一步驟,從而增加演算法的並行程度。

------------------總結----------------------

總的來說,對於快速排序演算法的改進主要集中在三個方面[1]:

1 選取乙個更好的中軸值

2 根據產生的子分割槽大小調整演算法

3 不同的劃分分割槽的方法

快速排序的改進

改寫partition演算法。要求 一次partition之後,小於基準元素key的數在左邊,等於key的在中間,大於key的在右邊 思路一 參照演算法導論上的思想,做出改進 i指向小於基準元素的序列的末尾,j指向等於基準元素的序列的末尾,k指向當前遍歷到的元素。include include us...

快速排序的改進

快速排序最壞情況下,要比較o n 2 次,但平均效能為nlogn,基本達到了比較類排序所需時間的的下界。核心 為 void qsort int data,int begin,int end int pivot,i,j if begin end return i begin j end pivot d...

快速排序的改進

快速排序是用途最廣的排序演算法之一,但是在最壞的情況下快速排序會退化成直接插入排序時間複雜度也就將為了o n 2 因此快速排序的改進也就是在選擇key元素上的選擇,選取乙個中位數可以保證快速排序演算法的效率。改進方法 1.選取中衛數作為key 2.排序前可以先將key和最後乙個元素交換,將key元素...