希爾排序(Shell Sort)也是插入排序的一種。也稱為縮小增量排序,是直接插入排序算法的一種更高效的改進版本。希爾排序是非穩定排序算法。該方法因DL.Shell於1959年提出而得名。
基本思想:
將待排序列划分為若干組,在每一組內進行插入排序,以使整個序列基本有序,然后再對整個序列進行插入排。
再從百度上貼個示例:
希爾增量:
希爾增量是指希爾提出了一種沖破二次時間屏障的算法。
Donald Shell 提出了一種沖破二次時間屏障的算法Shellsort(希爾排序),在希爾排序中希爾給出了一組增量序列:ht = N / 2, h[k] = h[k+1] / 2,即 {N/2, (N / 2)/2, ..., 1},這個序列就叫做希爾增量。這個是編寫希爾排序時最常用的序列,但卻不是最好的。其余的增量序列還有Hibbard:{1, 3, ..., 2^k-1},Sedgewick:{1, 5, 19, 41, 109...}該序列中的項或者是9*4^i - 9*2^i + 1或者是4^i - 3*2^i + 1。使用不同的增量對希爾排序的時間復雜度的改進將不一樣,甚至一點小的改變都將引起算法性能劇烈的改變。
優劣:
1. 不需要大量的輔助空間,和歸並排序一樣容易實現。
2. 希爾排序的時間復雜度與增量序列的選取有關,例如希爾增量時間復雜度為O(n²),而Hibbard增量的希爾排序的時間復雜度為O(),希爾排序時間復雜度的下界是n*log2n。
3. 希爾排序沒有快速排序算法快 O(n(logn)),因此中等大小規模表現良好,對規模非常大的數據排序不是最優選擇。
4. 希爾算法在最壞的情況下和平均情況下執行效率相差不是很多,而快速排序在最壞的情況下執行的效率會非常差。
代碼1 :
#include <stdio.h> void println(int array[], int len) { int i = 0; for(i=0; i<len; i++) { printf("%d ", array[i]); } printf("\n"); } void swap(int array[], int i, int j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; } void ShellSort(int array[], int len) // O(n*n) { int i = 0; int j = 0; int k = -1; int temp = -1; int gap = len; do { gap = gap / 3 + 1; for (i=gap; i<len; i+=gap) { k = i; temp = array[k]; for (j=i-gap; (j>=0) && (array[j]>temp); j-=gap) { array[j+gap] = array[j]; k = j; } array[k] = temp; } } while (gap > 1); } int main() { int array[] = {21, 25, 49, 25, 16, 8}; int len = sizeof(array) / sizeof(*array); println(array, len); ShellSort(array, len); println(array, len); return 0; }
#include<stdio.h> #include<math.h> #define MAXNUM 10 void main() { void shellSort(int array[],int n,int t);//t為排序趟數 int array[MAXNUM], i; for (i=0; i<MAXNUM; i++) scanf("%d",&array[i]); shellSort(array, MAXNUM, int(log(MAXNUM+1)/log(2)));//排序趟數應為log2(n+1)的整數部分 for(i=0;i<MAXNUM;i++) printf("%d ",array[i]); printf("\n"); } //根據當前增量進行插入排序 void shellInsert(int array[],int n,int dk) { int i,j,temp; for (i=dk; i<n; i++) { //分別向每組的有序區域插入 temp = array[i]; for(j=i-dk; (j>=i%dk) && array[j]>temp ;j-=dk)//比較與記錄后移同時進行 array[j+dk]=array[j]; if(j!=i-dk) array[j+dk]=temp;//插入 } } //計算Hibbard增量 int dkHibbard(int t,int k) { return int(pow(2,t-k+1)-1); } //希爾排序 void shellSort(int array[],int n,int t) { void shellInsert(int array[],int n,int dk); int i; for(i=1;i<=t;i++) shellInsert(array,n,dkHibbard(t,i)); }