1.什么是希尔排序
希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因D.L.Shell于1959年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
2.希尔排序图解
3.代码实现
public static void shellSort(int[] array) {
int d = array.length;
int mid = d / 2;
//获取希尔排序增量数组 这里使用希尔Hibbard增量的方式
List<Integer> incrementList = new ArrayList<>();
for (int i = 1; ; i++) {
int increment = (int) Math.pow(2, i) - 1;
if (increment < mid) {
incrementList.add(increment);
} else {
break;
}
}
while (incrementList.size() > 0) {
d = incrementList.remove(incrementList.size() - 1);
for (int i = 0; i < d; i++) {
for (int j = i; j < array.length; j += d) {
int temp = array[j];
int m;
for (m = j - d; m >= 0 && array[m] > temp; m -= d) {
array[m + d] = array[m];
}
array[m + d] = temp;
}
}
}
}
这里需要注意的是如果希尔增量按照减半的方式去递减的话会在一些特殊情况下效率较低,看下面这个例子
如果这个我们按照增量 4 2去递减 直到为1的时候才会去真正的操作,这样会使效率降低,对于这样的数组,希尔排序不但没有减少直接插入排序的工作量,反而白白增加了分组操作的成本。
为了保证分组粗调没有盲区,每一轮的增量需要彼此“互质”,也就是没有除1之外的公约数。
于是,人们相继提出了很多种增量方式,其中最具代表性的是Hibbard增量和Sedgewick增量。
Hibbard的增量序列如下:
1,3,7,15......
通项公式 2^k-1
利用此种增量方式的希尔排序,最坏时间复杂度是O(n^(3/2))
Sedgewick的增量序列如下:
1, 5, 19, 41, 109......
通项公式 9*4^k - 9*2^k + 1 或者 4^k - 3*2^k + 1
利用此种增量方式的希尔排序,最坏时间复杂度是O(n^(4/3))
关于这两种增量方式的时间复杂度,有些需要很复杂的数学证明,有些是人们的大致猜想,大家暂时不用纠结。
相同的元素在排序之后会改变原来的次序,由此可见希尔排序是一个不稳定排序。
4.希尔排序的效率
迄今为止,除了在一些特殊的情况下,还没有人能够从理论上分析希尔排序的效率 。有各种各 样基于试验的评估 ,估计它的时间级从 O(N^3/2)到 O(N^7/6)之间。