希爾排序是Donald Shell於1959年提出來的一種排序算法,它是第一批突破這個時間複雜度的算法之一。大話數據結構對這個算法的講解,我看得只知其一;不知其二的,以後網上找了下資料,發現維基百科對這個算法的講解很是不錯,特在此整理一波。算法
希爾排序是基於插入排序的如下兩點性質而提出改進方法的:數組
先上個維基百科的動圖,不知道大家看不看得懂,反正我不是很懂……bash
說說個人我的理解:數據結構
希爾排序其實就是直接插入排序的升級,原理就是先將整個待排序列按照某個增量(也稱步長)分割成若干個子序列分別進行直接插入排序,而後合併,以後依次縮小增量大小在進行排序,當增量足夠小(一般爲1)時,再對全體元素進行直接插入排序,而此時需排序的數據幾乎是已排好的了,因此此時插入排序較快。ui
固然若是你以爲文字比較乏味就看下面的這些例子吧spa
例如,假設有這樣一組數[9 1 5 8 3 7 4 6 2]
,若是咱們先以步長爲4進行分割,就是這樣:.net
9 1 5 8
3 7 4 6
2
複製代碼
而後咱們對每列進行排序(注意每列哦):3d
2 1 4 6
3 7 5 8
9
複製代碼
將上述四行數字,依序合併咱們獲得:[ 2 1 4 6 3 7 5 8 9 ]
。此時2已經往前移,而八、9已經在後兩位,而後再以2爲步長進行分割:code
2 1
4 6
3 7
5 8
9
複製代碼
繼續排序:cdn
2 1
3 6
4 7
5 8
9
複製代碼
合併獲得[ 2 1 3 6 4 7 5 8 9]
,此時序列已經基本有序,需交換數據的狀況大爲減小,這時整列進行直接插入排序效率就很是高。
最終完成排序過程,也就是步長爲1時,獲得最終序列爲:1 2 3 4 5 6 7 8 9
。
#include <stdio.h>
#define MAXSIZE 100 //用於要排序數組的最大值
typedef struct //定義一個順序表結構 {
int r[MAXSIZE+1]; //用於存儲要排序數組,r[0]用做哨兵或者臨時變量
int length; //用於存儲順序表的最大長度
}SqList;
void ShellSort(SqList *L) {
int i,j;
int gap=L->length; //獲取數組長度
for(gap/=2;gap>=1;gap/=2) //步長
for(i=gap+1; i<=L->length; i++) //從第gap+1個元素開始,由於r[0]被當作臨時變量
if(L->r[i] < L->r[i-gap]) //每一個元素與本身組內的數據進行直接插入排序
{
L->r[0]=L->r[i]; //把要交換的數據暫存的L->r[0]中
for(j=i-gap; j>0&&L->r[j] > L->r[0]; j-=gap)
L->r[j+gap] = L->r[j]; //記錄後移,查找插入位置
L->r[j+gap]=L->r[0]; //插入
}
}
int main() {
int i=0;
int array[] = {39,80,76,41,13,29,50,78,30,11,100,7,41,86};
SqList L;
L.length = sizeof(array)/sizeof(array[0]); //獲取數組長度
for(i=0;i<L.length;i++)
{
L.r[i+1]=array[i]; //把數組存入順序表結構
}
ShellSort(&L);
//輸出排序後的數組
for(i=0;i<L.length;i++)
{
printf("%d ",L.r[i+1]);
}
return 0;
}
複製代碼
可能有幾個步驟略難懂,這裏解釋下:
第17行:這裏的步長採用,最終判斷條件爲gap>=1,這裏無論你數組初始長度爲多少,除到最後均會等於1,而等於1時,就是執行最後一次循環,這個時候也就是全部元素進行直接插入排序。固然也可寫成gap>0。
第18行:在前面定義順序表結構時,咱們加多了一位,也就是把r[0]當作交換數據時的臨時變量。
第22~23行:對於這個循環咱們直接拿上面的例子中的一列進行講解(9 3 2)
:
當時,9和3進行了一次交換,變爲(3 9 2)
(位置爲1 5 9),以後在時,作出的交換如上圖所示(圖略差...),分爲三個步驟:
(3 9 9)
;(3 3 9)
;(2 3 9)
。步長的選取很是關鍵,可是步長的選擇沒有統一規定,也沒絕對的規律。只要知足最後一個步長爲1便可。Donald Shell最初建議步長選擇爲,雖然這樣去能夠比類的算法更好,但仍然有減小平均時間和最差時間的餘地。維基百科給出的部分步長與最壞狀況下複雜度有:
已知的最好步長序列是由Sedgewick提出的(1, 5, 19, 41, 109,...),該序列的項來自和這兩個算式。這項研究也代表「比較在希爾排序中是最主要的操做,而不是交換。」用這樣步長序列的希爾排序比插入排序要快,甚至在小數組中比快速排序和堆排序(後續博客整理),可是在涉及大量數據時希爾排序仍是比快速排序慢。