希尔排序的执行流程

在上一节,我们聊了一下插入排序算法,这种算法每次比较,都需要移动元素,给待插入数据腾位置,如果我们大部分的数据都是有序的,只有一个数据无序且最小并处于数组末端,我们移动这个小元素前面的数据其实没有任何意义。由此,诞生了希尔排序(也叫递减增量排序),希尔排序就是为了解决插入排序大量移动元素的问题。
希尔排序的思路是:初始化一个gap变量,每次跳跃gap步长进行元素比较。一轮比较之后,gap下标左边的元素和gap右边的元素大体上都有序了。我们举个例子:
8,7,2,9,6,1
第一轮比较,gap = (array.length / 2),gap = 3。我们需要比较的元素是8和9、7和6、2和1。比较后的数组演化为:
8,6,1,9,7,2。
之后,gap从现有基础上再次缩小2,gap = 3/2 ,gap = 1。这一轮比较,因为步长为1,所以相当于是对整个数组进行排序。我们需要比较的元素是8、6、1、9、7、2。
gap为1时,希尔排序停止。
我在网上找了一个动图,看着挺直观的,大家可以看一下。动图来源:https://www.cnblogs.com/fivestudy/p/10064969.html
在这里插入图片描述

java实现如下:

public static void main(String[] args) {
        int[] arr = {8, 7, 6, 5, 4, 3, 2, 1};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 希尔排序 针对有序序列在插入时采用交换法
     *
     * @param arr
     */
    public static void sort(int[] arr) {
        int n = arr.length;
        //增量gap,并逐步缩小增量
        for (int gap = n / 2; gap > 0; gap /= 2) {
            //从第gap个元素,逐个对其所在组进行直接插入排序操作
            for (int i = gap; i < arr.length; i++) {
                int j = i;
                while (j - gap >= 0 && arr[j] < arr[j - gap]) {
                    //插入排序采用交换法
                    swap(arr, j, j - gap);
                    //j递减gap,是和本组中的其他元素进行比较。
                    j -= gap;
                }
            }
        }
    }

    /**
     * 交换数组元素
     *
     * @param arr
     * @param a
     * @param b
     */
    public static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

希尔排序的关键逻辑是gap的选择,希尔本人给出的增量选择方法是:Array.length / 2,之后依次递减2即可。但是这种算法其实不是最优解,据说增量的选择是当前的一个数学难题,有科学家搞出了更优解,大家有兴趣自己查查吧。

时间复杂度分析
希尔排序时间复杂度是 O(n^(1.3-2))。比普通的插入排序快的多,但是数据量大的情况下,没有快速排序好。中等规模的数据,希尔排序的性能还可以。

空间复杂度分析
没有额外空间使用,空间复杂度为O(1)
原地排序算法分析
空间复杂度为O(1),所以是原地排序算法。
稳定排序算法分析
希尔排序是非稳定排序算法,看执行过程,很容易就能看出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值