快速排序及精確效能統計

2022-02-23 19:51:45 字數 2956 閱讀 1997

快速排序及精確效能統計

1.3 效能評估

快速排序使用分治法(divide and conquer)策略來把乙個序列(list)分為兩個子串行(sub-lists)。 步驟為:

從數列中挑出乙個元素,稱為 "基準"(pivot),

重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割槽退出之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作。

遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。

遞迴的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞迴下去,但是這個演算法總會退出,因為在每次的迭代(iteration)中,它至少會把乙個元素擺到它最後的位置去。

上面簡單版本的缺點是,它需要ω(n)的額外儲存空間,也就跟歸併排序一樣不好。額外需要的儲存器空間配置,在實際上的實現,也會極度影響速度和快取記憶體的效能。有乙個比較複雜使用原地(in-place)分割槽演算法的版本,且在好的基準選擇上,平均可以達到o(log n)空間的使用複雜度。 以上內容來自維基百科的快速排序。

我們不討論非原地分割槽的版本,先討論三種不同的實現方式。他們之間的實質差異並不大,主要集中在基準的選擇上。

1.2.1 單向劃分

這個版本是單向劃分,選擇串的最後一項作為基準,使用兩個變數 i,j 儲存索引,從左至右掃瞄,j中儲存著掃瞄進度一旦發現有大於基準的項立即與i後面一項交換。

function qsort(arr,l,u)

這個程式能夠滿足我們的需求是因為雖然我們沒有在第一次呼叫中交換位置,但是通過隨機函式rand可以獲得劃分基準。並且假設所有的項都是不相等的。目前為止,這個程式的執行時間與n成正比,並且儲存空間縮減為遞迴堆疊大小————與lgn成正比。

雖然在排序的時候,陣列下標非常重要,但是在當下場景中顯得有點多餘。我們把陣列下標省略掉,並對統計函式的形式改造。只接受乙個陣列大小的數值n來做為引數。

function profile3(n)

到這為止,我們還是使用的全域性變數做的統計,我們會自然而然的想到直接把這個函式做成乙個功能函式直接返回乙個結果值,表示演算法中的比較次數。下面給出函式:

function profile4(n)

好了,到目前為止,我們碰到的問題是,「當快速排序對n個元素的陣列進行一次排序時,需要進行多少次的比較?」現在對這個問題進行引申,「對n個項的串進行排序,需要比較的平均次數是多少?」我們對上面的**擴充套件並引出下面的**:

function profile5(n)

return sum/n;

}

如果輸入串最多只有乙個項,那麼quicksort將不會進行比較,對於更大的n值,這段**將考慮每個劃分元素m(從第乙個到最後乙個元素都是等可能的)並且確定在這個元素的位置上進行劃分 的執行開銷。然後這段**將統計這些開銷的總合(這樣就遞迴地解決了乙個大小為m-1的問題和乙個大小為n-m的問題),然後將總和除以n得到平均值並返回這個結果。

再觀察上面**,其實已經重複計算了中間結果。這種情況下,我們使用動態規劃來儲存中間結果,從而避免重複計算。有關動態規劃可以前往動態規劃演算法 這篇博文作詳細了解。這裡我們定義乙個表t[n+1],其中在t[n]中儲存c[n],並且按照公升序來計算它的值。用n表示n的最大值:

t[0]=0;

for(n=1;n<=n;n++)

我們再對程式做進一步的簡化,把n-1移到迴圈外部。

t[0]=0;

for(n=1;n<=n;n++)

我們不難發現,在上面**中t從i到n之間具有對稱性。例如,當n為4時,內部迴圈計算總和為: t1

+t2 + t3

+t4 + t4

+t3 + t2

+t1 因為都是加法,直接取二倍的累加值即可。利用這種對稱性,得到如下的**:

t[0]=0;

for(n=1;n<=n;n++)

仔細觀察**,可以發現兩層迴圈中還有有重複計算。所以把內層迴圈去掉,可以更加快速。

t[0]=0;sum=0;

for(n=1;n<=n;n++)

目前程式的執行時間已經是線性的,這裡的t陣列儲存了陣列中從元素0到元素n的真實平均值。對於每個從1到n的整數,程式將生成乙個表:

nsum

t[n]00

0100

2013

22.667

47.333

4.833517

7.46

31.8

10.3

752.4

13.486

879.371

16.921

假設我們不需要記錄所有的值,我們只關心給定的一部分數值,那麼我們把錶t改造成定長的。

sum=0,t=0;

for(n=1;n<=n;n++)

終於,這已經是最簡單的版本了,它的時間複雜度為線性,空間複雜度僅僅是1!

我們不得不驚嘆大師的功力,僅僅用4行**就可以精確計算出快速排序的平均比較次數,而且是最快速度,最少空間。這個優化過程是《計算機程式設計藝術》第三卷中給出的,作者knuth對hoare的數學表示式進行逐步優化,而jon bentley把這個數學過程全部用**的改進來一步步實現,也就顯得更加易於理解。

最後,向大師們致敬。同時還是那句話送給各位,less is more!

1 definition not found: 0

2 definition not found: 3

3 definition not found: 1

4 definition not found: 2

date: 2013-03-10 19:13:25 中國標準時間

author: 月窟仙人

org version 7.8.11 with emacs version 24

validate xhtml 1.0

八大排序 快速排序及效能分析

快速排序 quick sort 1 快速排序 它採用了 分治的策略 分治法 divide and conquermethod 的基本思想 將原問題分解為若干個規模更小但結構與原問題相似的子問題 遞迴地解這些子問題,然後將這些子問題的解組合為原問題的解。快速排序的基本思想 從數列中挑出乙個元素 一般是...

氣泡排序及快速排序

快速排序以乙個基準值,將無序列分成兩部分 左邊小於基準值,右邊大於基準值 然後遞迴。1.氣泡排序 2.快速排序 1.氣泡排序 氣泡排序 o n2 function bubblesort arr for i 0 i return arr 2.快速排序 快速排序 function quicksort a...

快速排序及分析

歸併排序將陣列分為兩個子陣列分別排序,並將有序的子陣列歸併使得整個陣列排序 快速排序通過乙個切分元素將陣列分為兩個子陣列,左子陣列小於等於切分元素,右子陣列大於等於切分元素,將這兩個子陣列排序也就將整個陣列排序了。public static void quicksort int list publi...