排序算法之希尔排序

基本介绍

希尔排序是希尔于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进后的高效版本,也称为缩小增量排序。

基本思想

排序算法之插入排序中插入排序很循规蹈矩,不管数组分布是怎么样,都会一步一步的对元素进行比较,移动,插入;假设这种序列[1,2,3,4,5,0],数组末端的0要回到首位置很是费劲,比较和移动元素均需n-1次。而希尔排序在数组中采用跳跃式分组的策略,通过某个增量将数组元素划分为若干组,然后分组进行插入排序,随后逐步缩小增量,继续按组进行插入排序操作,直至增量为1。希尔排序通过这种策略使得整个数组在初始阶段达到从宏观上看基本有序,小的基本在前,大的基本在后。然后缩小增量,到增量为1时,其实多数情况下只需微调即可,不会涉及过多的数据移动。

案例推导

我们先看个图解:
在这里插入图片描述
首先我们将初始数组根据数组长度/2的步长进行划分成5组[8,3], [9,5], [1,4],[7,6],[2,0];
我们对每一组进行插入排序,如[8,3]插入排序后就是[3,8];按照这种规则,第一轮希尔排序就变成了3,5,1,6,0,8,9,4,7,2;在按照数组长度/2/2的步长进行分组:[3,1,0,9,7],[5,6,8,4,2],对这两组进行插入排序,数组就变成了0,2,1,4,3,5,7,6,9,8;此时在缩小步长为数组长度/2/2/2,直到步长不大于0,最后将数组在进行简单插入排序就可以还得排好序的数组。

代码实现

分步实现代码:

 int[] arr = new int[]{8,9,1,7,2,3,5,4,6,0};

        //按照数组长度/2=10/2=5的步长进行分组
        int temp;
        for (int i = 5; i < arr.length; i++) {
            //开始从下标为0开始,依次找下标为 0,5;1,6;2,7;3,8;4,9
            for (int j = i - 5; j >= 0; j-=5) {
                //如果发现当前下标的比下一个步长的下标的值大,则进行替换
                if (arr[j] > arr[j+5]) {
                    temp = arr[j];
                    arr[j] = arr[j+5];
                    arr[j+5] = temp;
                }
            }
        }
        System.out.println("第一轮希尔排序结束:"+Arrays.toString(arr));

        //第二轮步长为5/2=2
        for (int i = 2; i < arr.length; i++) {
            for (int j = i - 2; j >= 0; j -= 2) {
                if (arr[j] > arr[j+2]) {
                    temp = arr[j];
                    arr[j] = arr[j+2];
                    arr[j+2] = temp;
                }
            }
        }
        System.out.println("第二轮希尔排序结束:"+Arrays.toString(arr));

        //第三轮步长为2/2=1
        for (int i = 1; i < arr.length; i++) {
            for (int j = i - 1; j >= 0; j -= 1) {
                if (arr[j] > arr[j+1]) {
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
        System.out.println("第三轮希尔排序结束:"+Arrays.toString(arr));

运行结果:

第一轮希尔排序结束:[3, 5, 1, 6, 0, 8, 9, 4, 7, 2]
第二轮希尔排序结束:[0, 2, 1, 4, 3, 5, 7, 6, 9, 8]
第三轮希尔排序结束:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

将代码合并整理为:

        int[] arr = new int[]{8,9,1,7,2,3,5,4,6,0};

        int temp,count = 0;
        //将数组长度/2,只要步长大于0就循环
        for (int gap = arr.length /2; gap > 0; gap/=2) {
            for (int i = gap; i < arr.length; i++) {
                //开始从下标为0开始,依次找下标为 0,5;1,6;2,7;3,8;4,9
                for (int j = i - gap; j >= 0; j-=gap) {
                    //如果发现当前下标的比下一个步长的下标的值大,则进行替换
                    if (arr[j] > arr[j+gap]) {
                        temp = arr[j];
                        arr[j] = arr[j+gap];
                        arr[j+gap] = temp;
                    }
                }
            }
            System.out.println("第"+(++count)+"轮希尔排序结束:"+Arrays.toString(arr));
        }

运行结果:

1轮希尔排序结束:[3, 5, 1, 6, 0, 8, 9, 4, 7, 2]2轮希尔排序结束:[0, 2, 1, 4, 3, 5, 7, 6, 9, 8]3轮希尔排序结束:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

上面的希尔排序采用的交换法,我们可以使用排序算法之插入排序中的移位法来实现。

移位法代码实现如下:

  int[] arr = new int[]{8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
        int temp, count = 0;
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            for (int i = gap, j; i < arr.length; i++) {
                int insertVal = arr[i];
                for (j = i - gap; j >= 0; j -= gap) {
                    if (insertVal < arr[j]) {
                        //移动数据
                        arr[j + gap] = arr[j];
                    } else {
                        break;
                    }
                }
                if (j + gap != i) {
                    arr[j + gap] = insertVal;
                }
            }
            System.out.println("第" + (++count) + "轮希尔排序结束:" + Arrays.toString(arr));
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值