希尔排序是一种插入排序,是插入排序的改进版本,也成为缩小增量排序(Diminishing Increment Sort)。
希尔排序原理是将待排序的数组元素按下标的一定增量分组,将其分成多个子序列,然后对各子序列进行插入排序,然后依次缩减增量重复执行排序操作,直至增量缩小为1时进行最后一次插入排序。
希尔排序增量(希尔增量)范围:[1, 待排序数组长度),取值一般从 待排序数组长度一半 开始,后续每次减半,直至增量为1。以长度为9的待排序数组为例:
- 第一个增量:
9 / 2 = 4 - 第二个增量:
4 / 2 = 2 - 第三个增量:
2 / 2 = 1
复杂度分析
希尔排序利用分组方式减少了插入排序的工作量,使得算法的平均时间复杂度低于O(n²)。
但在某些极端情况下,希尔排序的最坏时间复杂度就是O(n²),甚至比插入排序更慢,如以下待排序数列:
2 1 5 3 7 6 9 8
无论是以4为增量或以2为增量,元素都不会做任何交换,直至增量缩减到1时直接执行插入排序,此时,希尔排序不仅没有减少插入排序工作量,反而增加了分组成本。
Java 代码实现
import java.util.Arrays;
public class ShellSort {
public static void sort(int[] data) {
// 希尔排序增量(希尔增量)
int incremental = data.length;
while (incremental > 1) {
incremental = incremental / 2;
for (int x = 0; x < incremental; x++) {
for (int i = x + incremental; i < data.length; i = i + incremental) {
int temp = data[i];
int j;
for (j = i - incremental; j >= 0 && data[j] > temp; j = j - incremental) {
data[j + incremental] = data[j];
}
data[j + incremental] = temp;
}
}
System.out.println(Arrays.toString(data));
}
}
public static void main(String[] args) {
int[] data = {99, 5, 69, 33, 56, 13, 22, 55, 77};
sort(data);
}
}
运行结果
[56, 5, 22, 33, 77, 13, 69, 55, 99]
[22, 5, 56, 13, 69, 33, 77, 55, 99]
[5, 13, 22, 33, 55, 56, 69, 77, 99]
过程说明
- 第一次排序
希尔增量为
9 / 2 = 4,将待排序数组分组如下(使用字母标识)A组排序过程99(A), 5(B), 69(C), 33(D), 56(A), 13(B), 22(C), 55(D), 77(A)B组排序过程56(A), 5(B), 69(C), 33(D), 99(A), 13(B), 22(C), 55(D), 77(A) 56(A), 5(B), 69(C), 33(D), 77(A), 13(B), 22(C), 55(D), 99(A)C组排序过程56(A), 5(B), 69(C), 33(D), 77(A), 13(B), 22(C), 55(D), 99(A)D组排序过程56(A), 5(B), 22(C), 33(D), 77(A), 13(B), 69(C), 55(D), 99(A)第一次排序结束。56(A), 5(B), 22(C), 33(D), 77(A), 13(B), 69(C), 55(D), 99(A) - 第二次排序
希尔增量为
4 / 2 = 2,将待排序数组分组如下(使用字母标识)A组排序过程56(A), 5(B), 22(A), 33(B), 77(A), 13(B), 69(A), 55(B), 99(A)B组排序过程22(A), 5(B), 56(A), 33(B), 77(A), 13(B), 69(A), 55(B), 99(A) 22(A), 5(B), 56(A), 33(B), 69(A), 13(B), 77(A), 55(B), 99(A)22(A), 5(B), 56(A), 33(B), 69(A), 13(B), 77(A), 55(B), 99(A) 22(A), 5(B), 56(A), 13(B), 69(A), 33(B), 77(A), 55(B), 99(A) - 第三次排序
希尔增量为
2 / 2 = 2,即直接执行插入排序,过程22, 5, 56, 13, 69, 33, 77, 55, 99 5, 22, 56, 13, 69, 33, 77, 55, 99 5, 13, 22, 56, 69, 33, 77, 55, 99 5, 13, 22, 33, 56, 69, 77, 55, 99 5, 13, 22, 33, 55, 56, 69, 77, 99