当前位置:   article > 正文

【经典排序算法】4. 希尔排序_为什么希尔排序更快

为什么希尔排序更快

希尔排序是插入排序的一种改进版本。

可以看做是一种分组的插入排序,分组的变化受小组尾索引 i i i 和分组步长 s t e p step step控制,分好组后,对每个小组的元素执行插入排序即可。

时间复杂度分析:(希尔排序的时间性能优于插入排序的原因:)

  1. 当数组初态基本有序时直接插入排序所需的比较和移动次数都较少。

  2. 当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(N)和最坏时间复杂度O(N2)差别不大。

  3. 在希尔排序刚开始元素很无序的时候,步长step较大,分组较多,每组的元素数目少,所以组内插入排序速度很快。后面当元素基本有序了,步长step较小,虽然分组数减少,每组的元素数量多,但由于数组较接近于有序状态,所以新的一趟插入排序效率较高。

稳定性:
一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同组的插入排序中,相同元素可能在各自的插入排序中移动,最后稳定性就会被打乱,所以希尔排序是不稳定的。

应用:
希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。因此可以在几乎任何排序工作刚开始时,先使用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法。

代码如下:

public class Main {

    public static void main(String[] args) {
        int[] arr = {3, 3, 5, 6, 2, 1};
        System.out.print("排序前:");
        arrPrint(arr);
        ShellSort(arr);
        System.out.print("排序后:");
        arrPrint(arr);
    }

    // 希尔排序
    // 希尔排序是插入排序的改进版,意为将数组arr按照递减的步长step分组,
    // 同组的元素距离相邻一个step的长度,小组的尾索引记为i,每组分别使用插入排序,
    // 每次排序完步长step将按照减半来递减,构成新分组,再每组分别进行插入排序,
    // 以此循环下去,直至step=1,分组到最后只剩1组,小组尾索引i不断右移,即遍历完数组arr
    //
    // 实例中step将分别等于3,1。(想看过程可以利用arrPrint函数将中间过程打印)
    // 第一层for循环将step初始化为数组长度的一半,后循环减半,
    // 第二层for循环,锚定分组后每组的尾索引为i=j+step。由于同组元素距离为一个step,
    // 所以同组的元素可以通过j循环减step获得。
    public static void ShellSort(int[] arr) {
        int len = arr.length;
        for (int step = len / 2; step >= 1; step /= 2) {
            GroupInsertSort(arr, len, step);
        }
    }

    // (分组)插入排序
    // 还记得原来插入排序中i是从1开始的,就相当于分组后的i是从step开始的。
    // 遍历数为arr[i]=temp,这也就是待排序元素。
    // j = i - step为同组的i前一个元素索引,根据插入排序算法,
    // 如果j = i - step索引的元素arr[i]大于i索引的元素temp,
    // 则在同组内用while循环将大于temp的左边元素全部右移。
    // 注意指针要移动一个step的距离。
    private static void GroupInsertSort(int[] arr, int len, int step) {
        for (int i = step; i < len; i++) {
            int j = i - step;
            int temp = arr[j + step];
            while (j >= 0 && arr[j] > temp) {
                arr[j + step] = arr[j];
                j -= step;
            }
            if (j != i - step)
                arr[j + step] = temp;
        }
    }

    // 辅助函数:将int[] 打印出来
    private static void arrPrint(int[] arr) {
        StringBuilder str = new StringBuilder();
        str.append("[");
        for (int v : arr) {
            str.append(v + ", ");
        }
        str.delete(str.length() - 2, str.length());
        str.append("]");
        System.out.println(str.toString());
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

实例的动画演示如下:

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/786861
推荐阅读
相关标签
  

闽ICP备14008679号