演算法學習記錄 排序 希爾排序

2021-10-01 19:09:06 字數 2891 閱讀 1485

希爾排序:

直接插入排序在在本身數量比較少的時候情況下效率很高,如果待排數的數量很多,其效率不是很理想。

回想一下直接插入排序過程,排序過程中,我們可以設定一條線,左邊是排好序的,右邊則是乙個乙個等待排序,

如果最小的那個值在最右邊,那麼排這個最小值的時候,需要將所有元素向右邊移動一位。

是否能夠減少這樣的移位呢?

我們不希望它是一步一步的移動,而是大步大步的移動。希爾排序就被發明出來了,它也是當時打破效率

o(n2)的演算法之一。希爾排序演算法通過設定乙個間隔,對同樣間隔的數的集合進行插入排序,此數集合中的元素

移位的長度是以間隔的長度為準,這樣就實現了大步位移。但是最後需要對元素集合進行一次直接插入排序,所以

最後的間隔一定是1。

下面舉乙個例子:

第一趟希爾排序,間隔為4

第二趟排序:間隔是2

第三趟 間隔為1,即 直接插入排序法:

有人問,這個間隔怎麼確定,這是個數學難題,至今沒有解答。但是通過大量的實驗,還是有個經驗值。

減小間隔

上面已經演示了以4為初始間隔對包含10個資料項的陣列進行排序的情況。對於更大的陣列開始的間隔也應該更大。然後間隔不斷減小,直到間隔變成1。

舉例來說,含有1000個資料項的陣列可能先以364為增量,然後以121為增量,以40為增量,以13為增量,以4為增量,最後以 1為增量進行希爾排序。用來形成間隔的數列被稱為間隔序列。這裡所表示的間隔序列由knuth提出,此序列是很常用的。數列以逆向形式從1開始,通過遞迴表示式

h=3*b+1

來產生,初始值為1。

在排序演算法中,首先在乙個短小的迴圈中使用序列的生成公式來計算出最初的間隔。h值最初被賦為1,然後應用公式h=3*h+1生成序列1,4,13,40,121,364,等等。當間隔大於陣列大小的時候,這個過程停止。對於乙個含有1000個資料項的陣列,序列的第七個數字,1093就太大了。因此,使用序列的第六個數字作為最大的數字來開始這個排序過程,作364-增量排序。然後,每完成一次排序全程的外部迴圈,用前面提供的此公式倒推式來減小間隔:

h=(h-1)/3

這個倒推的公式生成逆置的序列364,121,40,13,4,1。從364開始,以每乙個數字作為增量進行排序。當陣列用1-增量排序後,演算法結束。

希爾排序比插入排序快很多,它是基於什麼原因呢?當h值大的時候,資料項每一趟排序需要移動元素的個數很少,但資料項移動的距離很長。這是非常有效率的。當h減小時,每一趟排序需要移動的元素的個數增多,但是此時資料項已經接近於它們排序後最終的位置,這對於插入排序可以更有效率。正是這兩種情況的結合才使希爾排序效率那麼高。

注意後期的排序過程不撤銷前期排序所做的工作。例如,已經完成了以40-增量的排序的陣列,在經過以13-增量的排序後仍然保持了以40-增量的排序的結果。如果不是這樣的話,希爾排序就無法實現排序的目的。

其他間隔序列

選擇間隔序列可以稱得上是一種魔法。至此只討論了用公式h=h*3+1生成間隔序列,但是應用其他間隔序列也取得了不同程式的成功,只是乙個絕對的條件,就是逐漸減小的間隔最後一定要等於1,因此最後一趟排序是一次普通的插入排序。

在希爾的原稿中,他建議初始的間距為n/2,簡單地把每一趟排序分成了兩半。因此,對於n=100的陣列逐漸減小的間隔序列為50,25,12,6,3,1。這個方法的好處是不需要在不開始排序前為找到初始的間隔而計算序列;而只需要用2整除n。但是,這被證明並不是最好的數列。儘管對於大多數的資料來說這個方法還是比插入排序效果好,但是這種方法有時會使執行時間降到o(n2),這並不比插入排序的效率更高。

這個方法的乙個變形是用2.2而非2來整除每乙個間隔。對於n=100的陣列來說,會產生序列45,20,9,4,1。這比用2整除顯著改善了效果,因為這樣避免了某些導致時間複雜度為o(n2)的最壞情況的發生。不論n為何值,都需要一些額外的**來保證序列的最後取值為1。這產生了和清單中所列的knuth序列差不多的結果。

遞減數列的另乙個可能是

if(h<5)

h=1;

else

h=(5*h-1)/11;

間隔序列中的數字互質通常被認為很重要:也就是說,除了1之外它們沒有公約數。這個約束條件使每一趟排序更有可能保持前一趟排序已排好的效果。希爾最初以n/2為間隔的低效性就是歸咎於它沒有遵守這個準則。

或許還可以設計出像如上講述的間隔序列一樣好的間隔序列。但是不管這個間隔序列是什麼,都應該能夠快速地計算,而不會降低演算法的執行速度。

這就是希爾演算法的思想:

先將整個待排記錄序列分割成為若干子串行分別進行直接插入排序,待整個序列中的記錄「基本有序」時,在對全體進行一次直接插入排序。

**:因為希爾排序就是有增量的直接插入排序,所以將原先直接插入**修改一下,把步進長度改為增量即可。

1

void shellsort(mydatatype *ary,int

len)

223 j=j-increment;24}

25}26}

27 }

完整**:

1 #include "

stdafx.h"2

34 typedef int

mydatatype;

5 mydatatype src_ary[10] = ;67

void prt_ary(mydatatype *ary,int

len)

814 printf("\n"

);15}16

void shellsort(mydatatype *ary,int

len)

1738 j=j-increment;39}

40}41}

42}4344

45int _tmain(int argc, _tchar*ar**)

46

結果:

演算法學習 7 4希爾排序

希爾排序最壞情況o n 2 增量的選擇不同,其平均複雜度也不同 希爾排序的效能可以在實踐中接受,其簡單特點使其對於適度的大量輸入 數以萬計 經常和你選用的演算法。希爾排序的實質就是分組插入排序,該方法又稱縮小增量排序,因dl shell於1959年提出而得名。該方法的基本思想是 先將整個待排元素序列...

排序演算法學習記錄

口述思路 內外雙迴圈,內迴圈中當 n n 1 時,進行資料對調,目的就是為了讓n永遠為最小的數,以此類推,我們的排序一般都是從左向右,左邊是最小的,右邊是最大的。口述思路 特點就是運用遞迴,單個迴圈體,預設要將第乙個n設為middle變數,然後迴圈開始後,將大於middle的記錄到right變數中 ...

排序演算法學習記錄

特點 從左到右開始,右邊每次都輪結束都出現乙個最大數。即右邊的數依次先排列好。時間複雜度 o n 2 空間複雜度 o 1 氣泡排序 第一層迴圈,若上一回遍歷結束,有交換資料操作 繼續挨個遍歷。每完成一次找到乙個最大數置於後邊。第二層遍歷,每次遍歷都比上一回,少遍歷乙個數 判斷大小。void mpso...