排序算法(三)希尔排序

235 阅读3分钟

希尔排序是一种插入排序,是插入排序的改进版本,也成为缩小增量排序(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,将待排序数组分组如下(使用字母标识)
    99(A), 5(B), 69(C), 33(D), 56(A), 13(B), 22(C), 55(D), 77(A)
    
    A组排序过程
    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)
    
    B组排序过程
    56(A), 5(B), 69(C), 33(D), 77(A), 13(B), 22(C), 55(D), 99(A)
    
    C组排序过程
    56(A), 5(B), 22(C), 33(D), 77(A), 13(B), 69(C), 55(D), 99(A)
    
    D组排序过程
    56(A), 5(B), 22(C), 33(D), 77(A), 13(B), 69(C), 55(D), 99(A)
    
    第一次排序结束。
  • 第二次排序 希尔增量为 4 / 2 = 2,将待排序数组分组如下(使用字母标识)
    56(A), 5(B), 22(A), 33(B), 77(A), 13(B), 69(A), 55(B), 99(A)
    
    A组排序过程
    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)
    
    B组排序过程
    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