希爾排序是插入排序中的一種,前面一篇文章(點擊查看)中提到的插入排序演算法準確的來說應該稱為“直接插入排序演算法”,而這裡介紹的希爾排序演算法是對直接插入排序演算法改進之後形成的一種演算法,該演算法是由D.L Shell於1959年提出的,它也因此而得名,又稱縮小增量排序演算法。
基本思想
設初始序列有n個元素,選定一個小於n大於或等於1的整數gap作為間隔,將全部元素分成gap個子序列,所有距離為gap的元素放在同一個子序列中,在每個子序列中分別採用直接插入演算法進行排序;然後縮小間隔gap,如令gap=gap/2,重複上面的子序列劃分和子序列排序動作;直到最後去gap=1,將所有的元素放到一個序列中為止。
簡單樣本
初始序列:21 25 49 25 16 8
第一步:
第二步:
第三步:
演算法說明
開始時gap的值較大,子序列中的元素較少,排序速度比較快;隨著排序進展,gap的值逐漸減小,子序列中的元素增多,不過由於前面排序工作的基礎,大多數元素已基本有序,所以排序速度依然是比較快的。
對於gap值的取法有很多種。最初Shell提出取gap=n/2,gap=gap/2,直到gap=1。後來Knuth提出取gap=gap/3+1,另外還有人認為gap都去奇數比較好,也有人說讓各個gap值互質為好。另外,由上面的執行個體可以看出:該演算法是不穩定的演算法。
演算法分析
對特定的待排序序列,可以準確的估算元素的比較次數和移動次數;但是,想要弄清楚元素比較次數和移動次數與增量選擇之間的依賴關係,並給出完整的數學分析,還沒有人能夠做到。另外,由上面的執行個體可以看出:該演算法是不穩定的演算法。
演算法實現
C語言:
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX 10 #define SWAP(x,y) {int t; t = x; x = y; y = t;} void shellsort(int[]); int main(void) { int number[MAX] = {0}; int i; srand(time(NULL)); printf("排序前:"); for(i = 0; i < MAX; i++) { number[i] = rand() % 100; printf("%d ", number[i]); } shellsort(number); return 0; } void shellsort(int number[]) { int i, j, k, gap, t; gap = MAX / 2; while(gap > 0) { for(k = 0; k < gap; k++) { for(i = k+gap; i < MAX; i+=gap) { for(j = i - gap; j >= k; j-=gap) { if(number[j] > number[j+gap]) { SWAP(number[j], number[j+gap]); } else break; } } } printf("\ngap = %d:", gap); for(i = 0; i < MAX; i++) printf("%d ", number[i]); printf("\n"); gap /= 2; } }
JAVA語言:
public class ShellSort { public static void sort(int[] number) { int gap = number.length / 2; while(gap > 0) { for(int k = 0; k < gap; k++) { for(int i = k+gap; i < number.length; i+=gap) { for(int j = i - gap; j >= k; j-=gap) { if(number[j] > number[j+gap]) { swap(number, j, j+gap); } else break; } } } gap /= 2; } } private static void swap(int[] number, int i, int j) { int t; t = number[i]; number[i] = number[j]; number[j] = t; }}
THE END!