1. 程式人生 > >排序的穩定性

排序的穩定性

before font .com images log 但是 交換 第一個 pan

什麽是排序穩定性?  

  通俗地講就是在排序前A的位置是 i ,B的位置是 j,此時 i < j,則如果在排序後A的位置還是在B之前,那麽稱它是穩定的。

它的好處是,如果排序算法是穩定的,那麽第一個排序結果可以為另一個排序所用。比如基數排序,先按低位排序,逐次按高位排序,低位相同的元素其順序在高位也相同時是不會改變的。

首先給出一張在前一個博客“時間復雜度入門理解”中出現過的一副圖,給出相關排序的穩定性:

  技術分享圖片

接下來,將解釋圖中某些排序是不穩定的的原因。

I)為什麽希爾排序不穩定?

A:首先要知道 Shell 排序是基於插入排序的優化排序,插入排序每次本身只能插入一位數據,希爾排序按照步長對多個元素進行插入排序。我們知道一次插入排序是穩定的,但是同時對多組數據進行插入排序,很明顯就穩定了,舉例:

有這樣一組數:[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ]

以第一輪是步長為5的希爾排序為例:

Before Shell Sort:

技術分享圖片

After Shell Sort:

技術分享圖片

很明顯,之前 94 相對於 33 的位置就變了,這就是同時進行多次插入排序所導致的不穩定性。

II)為什麽快速排序不穩定?

A:快排的思想是先設一個中樞元素(也稱是基準數,對照用),對兩遍進行排列,需要滿足左邊的元素都比中樞元素小,右邊元素都比中樞元素大,隨後對左和右的子序列也進行這樣的操作(分治)。而該排序不穩定的關鍵就是中樞元素在調換到序列中間的時候,會破壞了原來位於中央的元素的穩定性,比如有一個序列:

6 1 2 7 9 3 4 5 10 8 ,我們定義 6 為中樞元素

進行第一輪快排後,得3 1 2 5 4 6 9 7 10 8

這樣操作就會把 3 的穩定性破壞。所以快排是一個不穩定的排序算法,不穩定發生在中樞元素的交換時刻。

III)為什麽選擇排序是不穩定的?

A:選擇排序的操作是這樣:先在未排序的序列中選擇最小的元素(或最大的元素),把它放入第一個位置,再在剩余未排序序列中選擇第二小的,放在第二個位置...以此類推,直到所有序列排序完畢。但是,這樣直接讓最小元素與第一個位置上的元素進行交換,會破壞第一個元素的穩定性。

舉個例子:6 2 1 7 9 3 4 5 10 8

在6 和 1 的交換同時,6 與 2的穩定性就被破壞了。

IV)為什麽堆排序是不穩定的?

A:堆的結構是第 i 個結點的左子結點為 2i ,右子結點為2i + 1,子結點 i 的父結點的位置在 floor( (i-1)/2 ),最大堆要求父結點要大於它的兩個子結點,最小堆要求父結點要小於它的兩個子結點。而堆排序就是移除位於第一個數據的根結點,並做做大堆調整的遞歸運算。

在一個長為n的序列中,首先從第 n/2 個結點和其子結點一共三個結點開始選擇是最大堆還是最小堆,這三個元素的選擇當然並不會影響穩定性。但是之後第n/2 -1 ,n/2 -2, ... 2, 1 個結點開始選擇就會影響穩定性了。因為有可能第 n/2 -2 個父結點把其後的一個元素交換了,而第 n/2 -3 個父結點的後一個結點卻沒有被交換,那麽它們之間的穩定性就被破壞了。

註意

  排序算法是否為穩定的是由具體算法決定的,不穩定的算法在某種條件下可以變為穩定的算法,而穩定的算法在某種條件下也可以變為不穩定的算法。比如冒泡,若讓交換的條件改成 r[j] >= r[j+1],兩個相等的記錄就會交換位置,從而變成不穩定的算法。

排序的穩定性