简介:希尔排序的实质其实是分组插入排序,再通俗的讲就是缩小增量排序,是一种比O(N^2)要好的排序算法,当然,是比不上O(NlgN)的算法.
原理:将整个待排元素序列分割成若干个子序列(由相隔某个增量值gap的元素组成),再分别对每个子序列进行快速插入排序,然后减少gap再进行快速插入排序,待gap减少到足够小,最好是减少到1的时候进行最后一次快速插入排序(gap为1的时候,相当于整个数组是一个子序列,但是经过前面的若干次重排,整个数组基本有序,最后进行一次微排即可),此时,整个数组就是有序的.因为快速插入排序在数组为基本有序时,效率是很高的,比选择排序和插入排序要高效的多,当然在gap的减少策略上,不同的减少策略也会带来不一样的效率.
原始数组如下:
增量计算方式gap = length / 2 采用gap = gap / 2
①gap = 10 / 2 = 5
按照相隔为5的原则 将整个数组按照以下顺序分割为了5组,每组分别进行快速插入排序.这样在这五组中就有序了
②gap = 5 / 2 = 2
按照相隔为2的原则,将整个数组分割为了2组,再次进行快速插入排序.
③gap = 2 / 2 = 1
即对数组进行一次快速插入排序即可.结果如下
Java代码如下:
public static void sort(int[] arr) {
long start = System.currentTimeMillis();
int i, j, gap;
for (gap = arr.length / 2; gap > 0; gap = gap / 2) {// 控制分组
for (i = 0; i < gap; i++) {//控制组群排序
for (j = i + gap; j < arr.length; j += gap) {// 控制单组排序
int tmp = arr[j];
int k = j - gap;
while (k >= 0 && arr[k] > tmp) {
arr[k + gap] = arr[k];
k = k - gap;
}
arr[k + gap] = tmp;
}
}
}
System.out.println("time=" + (System.currentTimeMillis() - start) + "毫秒");
}
经过优化的增量序列如Hibbard经过复杂证明可使得最坏时间复杂度为O(n3/2)
public static void betterSort(int[] arr){
long start = System.currentTimeMillis();
int n = arr.length;
// 计算 increment sequence: 1, 4, 13, 40, 121, 364, 1093...
int h = 1;
while (h < n/3) h = 3*h + 1;
while (h >= 1) {
// h-sort the array
for (int i = h; i < n; i++) {
// 对 arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序
int e = arr[i];
int j = i;
for ( ; j >= h && e < arr[j - h] ; j -= h)
arr[j] = arr[j-h];
arr[j] = e;
}
h /= 3;
}
System.out.println("betterSort=" + (System.currentTimeMillis() - start) + "毫秒");
}