排序算法(四) 希尔排序(插入排序的进化)

参考
Java排序算法(四):希尔排序
常见排序算法 - 希尔排序 (Shell Sort)

希尔排序算法是按其设计者希尔(Donald Shell)的名字命名,该算法由1959年公布,是插入排序的一种更高效的改进版本。它的作法不是每次一个元素挨一个元素的比较。而是初期选用大跨步(增量较大)间隔比较,使记录跳跃式接近它的排序位置;然后增量缩小;最后增量为 1 ,这样记录移动次数大大减少,提高了排序效率。希尔排序对增量序列的选择没有严格规定。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率
  • 但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位

假设有数组 array = [80, 93, 60, 12, 42, 30, 68, 85, 10],首先取 d1 = 4,将数组分为 4 组,如下图中相同颜色代表一组:

排序算法(四) 希尔排序(插入排序的进化)_第1张图片
增量为4

然后分别对 4 个小组进行插入排序,排序后的结果为:

排序算法(四) 希尔排序(插入排序的进化)_第2张图片
同颜色组内排序

然后,取 d2 = 2,将原数组分为 2 小组,如下图:

排序算法(四) 希尔排序(插入排序的进化)_第3张图片
增量为2

然后分别对 2 个小组进行插入排序,排序后的结果为:

排序算法(四) 希尔排序(插入排序的进化)_第4张图片
同颜色组内排序

最后,取 d3 = 1,进行插入排序后得到最终结果:

排序算法(四) 希尔排序(插入排序的进化)_第5张图片
增量为1

该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。

public class ShellSort {

    public static void main(String[] args) {
        int[] arr = { 6, 5, 3, 1, 8, 7, 2, 4 };
        System.out.println("排序之前:");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }

        // 希尔排序
        shellSort(arr);

        System.out.println();
        System.out.println("排序之后:");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }

    /**
     * 希尔排序
     */
    private static void shellSort(int[] arr) {
        int j;
        for (int gap = arr.length / 2; gap > 0; gap = gap / 2) {
            for (int i = gap; i < arr.length; i++) {
                int tmp = arr[i];
                for (j = i; j >= gap && tmp < arr[j - gap]; j = j - gap) {
                    arr[j] = arr[j - gap];
                }
                arr[j] = tmp;
            }
        }
    }

}

希尔排序时间复杂度:O(nlogn)
希尔排序并不是一种稳定的排序算法。

你可能感兴趣的:(排序算法(四) 希尔排序(插入排序的进化))