數據結構63:希爾排序算法(縮小增量排序)


希爾排序,又稱“縮小增量排序”,也是插入排序的一種,但是同前面幾種排序算法比較來看,希爾排序在時間效率上有很大的改進。

在使用直接插入排序算法時,如果表中的記錄只有個別的是無序的,多數保持有序,這種情況下算法的效率也會比較高;除此之外,如果需要排序的記錄總量很少,該算法的效率同樣會很高。希爾排序就是從這兩點出發對算法進行改進得到的排序算法。

希爾排序的具體實現思路是:先將整個記錄表分割成若干部分,分別進行直接插入排序,然后再對整個記錄表進行一次直接插入排序。

例如無序表{49,38,65,97,76,13,27,49,55,4}進行希爾排序的過程為:

  • 首先對 {49,13},{38,27},{65,49},{97,55},{76,4} 分別進行直接插入排序(如果需要調換位置也只是互換存儲位置),如下圖所示:

 

上圖中兩兩進行比較,例如 49 和 13 進行比較,13<49,所以交換存儲位置。
 
  • 通過一次排序,無序表中的記錄已基本有序,此時還可以再進行一次分割,如下圖所示:

  • 經過兩次分割,無序表中已基本有序,此時對整張表進行一次直接插入排序(只需要做少量的比較和插入操作即可),最終希爾排序的結果為:


 

希爾排序的過程中,對於分割的每個子表,其各自包含的記錄在原表中並不是相互挨着的,而是相互之間相隔着某個固定的常數。例如上例中第一次排序時子表中的記錄分割的常量為 5,第二次排序時為 3。

通過此種方式,對於關鍵字的值較小的記錄,其前移的過程不是一步一步的,而是跳躍性的前移,並且在最后一次對整表進行插入排序時減少了比較和排序的次數。

一般在記錄的數量多的情況下,希爾排序的排序效率較直接插入排序高。

希爾排序的具體代碼實現:

#include <stdio.h>
#include <stdlib.h>
#define SIZE 15
typedef struct
{
int key;   // 關鍵字的值 }SLNode;
typedef
struct
{ SLNode r[SIZE];  
// 存儲記錄的數組 int length;     // 記錄數組中記錄的數量 }SqList;
// 希爾排序的實現函數,其中 dk 表示增值量 void ShellInsert(SqList *L, int dk)
{
//從 dk+1 個記錄起,每間隔 dk 個記錄就調取一個進行直接插入排序算法 for (int i=dk+1; i<=L->length; i++)
   {
// 如果新調取的關鍵字的值,比子表中最后一個記錄的關鍵字小,說明需要將該值調換位置 if (L->r[i].key<L->r[i-dk].key)
     {
int j; // 記錄表中,使用位置下標為 0 的空間存儲需要調換位置的記錄的值 L->r[0] = L->r[i]; // 做直接插入排序,如果下標為 0 的關鍵字比下標為 j 的關鍵字小,則向后一行下標為 j 的值,為新插入的記錄騰出空間。 for (j=i-dk; j>0 && (L->r[0].key<L->r[j].key); j-=dk)
       { L
->r[j+dk] = L->r[j]; } // 跳出循環后,將新的記錄值插入到騰出的空間中,即完成了一次直接插入排序 L->r[j+dk] = L->r[0]; } } }
//希爾排序,通過調用不同的增量值(記錄),實現對多個子表分別進行直接插入排序 void ShellSort(SqList *L, int dlta[], int t)
{
for (int k=0; k<t; k++)
  { ShellInsert(L, dlta[k]); } }
int main(int argc, const char *argv[])
{
int dlta[3] = {5, 3, 1};  // 用數組來存儲增量值,例如 5 代表每間隔5個記錄組成一個子表,1表示每間隔一個,也就是最后一次對整張表的直接插入排序 SqList *L = (SqList*)malloc(sizeof(SqList)); L->r[1].key = 49; L->r[2].key = 38; L->r[3].key = 64; L->r[4].key = 97; L->r[5].key = 76; L->r[6].key = 13; L->r[7].key = 27; L->r[8].key = 49; L->r[9].key = 55; L->r[10].key = 4; L->length = 10; // 調用希爾排序算法 ShellSort(L, dlta, 3); // 輸出語句 for (int i=1; i<=10; i++)
   { printf(
"%d ", L->r[i].key); } return 0; }
運行結果:
4 13 27 38 49 49 55 64 76 97

 

提示:經過大量的研究表明,所選取的增量值最好是沒有除 1 之外的公因子,同時整個增量數組中最后一個增量值必須等於 1 ,因為最后必須對整張表做一次直接插入排序算法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM