標籤:htm 位置 疑問 com 種類型 new flow 今天 使用
前言:
今天淩晨在臨睡前隨意翻看了 @啊哈磊 的坐在馬桶上看演算法:快速排序,對快速排序演算法有了新的認識。在此之前,我只對冒泡排序演算法有一些瞭解。
在此感謝 @啊哈磊 的耐心講解。
已知一個一維數組arr,包含17個元素:
int[] arr = new int[] { 13, 25, 6, 84, 71, 63, 96, 49, 7, 52, 30, 28, 1, 74, 93, 69, 40 };
我們從中選擇任意一個數作為基準,例如25。
另外,聲明兩個指標變數a和b,將他們置於數組的兩端,即13和40。
左側指標a負責找比基準值大的數,它從左向右移動;
右側指標b負責找比基準值小的數,它從右向左移動。
當它們其中一個找到合適的數時,則在此停留並等待另一個指標找到合適的數。如果另一個指標也找到了合適的數,那麼就令它們交換得到的數(指標b先開始移動)。
第一次的停留結果:
84,1
OK,將這兩個數交換位置。這就變成了:
(1)13, 25, 6, 1, 71, 63, 96, 49, 7, 52, 30, 28, 84, 74, 93, 69, 40
a b
此時,指標a停留位置的數值是1,指標b停留位置的數值是84。
第二次停留結果:
71,7
再將這兩個數交換位置:
(2)13, 25, 6, 1, 7, 63, 96, 49, 71, 52, 30, 28, 84, 74, 93, 69, 40
a b
此時,指標a停留位置的數值是7,指標b停留位置的數值是71。
這時我們會發現,7與71之間的數都比25大。這意味著,如果指標b繼續向左搜尋比25小的數值,必將與指標a相遇。即:指標a與b都處在7的位置。
OK,將指標a和b共同停留的7與基準數25交換:
(3)13, 7, 6, 1, 25, 63, 96, 49, 71, 52, 30, 28, 84, 74, 93, 69, 40
ab
這時我們會發現:基準數25左側數列中的每個數都比25小,而右側數列中的每個數都比25大。這樣,我們就能將這個數組以基準值25為界限,劃分為兩個數列:
13, 7, 6, 1
63, 96, 49, 71, 52, 30, 28, 84, 74, 93, 69, 40
而在這兩個數列中,第一個數列的左側指標停留的值和第二個數列的右側指標停留的值分別與與數組的左右側指標一致。
到這裡,可能有些人會有疑問:如果在第(2)步之後,率先移動的是指標a而不是指標b,那麼是否可以呢?
我可以很明確地對你說——完全可以!
至於為什麼,我們接下來繼續解析:
假如我們率先移動的是指標a而不是指標b,那麼在指標a率先移動並停留於大於基準數的數值63後,指標b在向左尋找小於基準數25的數值時,將與指標a相遇。即:
(4)13, 25, 6, 1, 7, 63, 96, 49, 71, 52, 30, 28, 84, 74, 93, 69, 40
ab
我們會觀察到:63左側的所有數都不大於25,而63及右側的所有數都不小於25。
同樣,我們可以將數組(4)分為兩個數列:
13, 25, 6, 1, 7
63, 96, 49, 71, 52, 30, 28, 84, 74, 93, 69, 40
而在數列(3)中,我們會發現(4)的結論同樣使用於(3):
13, 7, 6, 1, 25, 63, 96, 49, 71, 52, 30, 28, 84, 74, 93, 69, 40
ab
結論與(4)類似:25左側的所有數都不大於25,而25及右側的所有數都不小於25。
只不過在(3)中,我們得出的結論是:25左側的所有數都小於25,而右側的所有數都大於25。
根據上面的推導過程,我們很容易再將這兩種類型的子數列依照新的基準數進行排序。
其實快速排序與冒泡排序的最大不同之處在於,後者的排序是漸進式(每次比較的兩個數都相鄰),而前者的排序是跳躍式。當預排序的數組足夠長且比較次數一定時,涉及更多新的數值的跳躍式無疑具有漸進式不可比擬的優點。當然,前者與後者在最壞情況下的比較次數是相等的。
不過,不要忘了:快速排序的基準必須是當前排序數列的最大值與最小值之間的一個數。否則,很容易發生StackOverflowException。
快速排序的基本原理