希爾排序,又稱“縮小增量排序”,也是插入排序的一種,但是同前面幾種排序算法比較來看,希爾排序在時間效率上有很大的改進。
在使用直接插入排序算法時,如果表中的記錄只有個別的是無序的,多數保持有序,這種情況下算法的效率也會比較高;除此之外,如果需要排序的記錄總量很少,該算法的效率同樣會很高。希爾排序就是從這兩點出發對算法進行改進得到的排序算法。
希爾排序的具體實現思路是:先將整個記錄表分割成若干部分,分別進行直接插入排序,然后再對整個記錄表進行一次直接插入排序。
例如無序表{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 ,因為最后必須對整張表做一次直接插入排序算法。