希尔排序算法(java实现)

希尔排序也叫缩小增量排序,是对插入排序的一种改进,同时该算法也是冲破O(n^{2})的第一批算法之一。插入排序的思路是每次挑选一个数值,并把它插入到数列的合适位置,具体算法实现可见我之前的博客基础算法——插入排序-CSDN博客,通过分析可以看到,插入排序每次只能为一个数值确定位置,效率比较低,所以在直接插入排序的基础上,进行了升级优化,就有了希尔排序。

插入排序的操作对象是整个数列,每一轮排序只能确定一个数的位置,而且有时还要遍历整个数列寻找合适数值,数列短的话还好,如果在数列很长,最小值又在最末端的情况下,就需要逐个往前比较,直到第一个位置,效率很低,所以对于顺序完全颠倒的数列来说,插入排序就比较慢,而对于大致有序的数列,插入排序效率就很快了。

因此需要对插入排序进行适当优化,我们可以先将数列进行一个简单的预排序,让数列变得比较有序,然后再充分发挥插入排序的优势,对这个大致有序的数列进行排序,最终完成排序。

这就是希尔排序的基本原理,它基于插入排序,又做了一定的优化

希尔排序的原理是这样的:

先按照一定的规则从数列中抽一些数字,对这些数字进行一个排序,然后把这些数字放回原来的位置,比如对数列【3,8,1,2,5,9,4,7,6,0】进行从小到大排序,我们先抽3,2,4,0这几个数,然后使用插入排序算法对其进行排序。

这四个数的排序结果是0,2,3,4,所以,我们再把排好序的这四个数字,还放回到原来的位置,其他数字的位置或索引都保持不变。数列看起来有序一些了,变成了:

接着我们再抽取0,1,5,3,6这几个数字,继续使用插入排序算法对其进行排序。

这五个数的排序结果是0,1,3,5,6,数列更加有序,变成了:

对于上面这样的数列,就可以认为是大致有序了,最后直接对整个数列使用直接插入排序,这里充分利用了插入排序的优势,整个数列的排序就很顺畅了。

用计算机语言来梳理上面的流程:

先确定一个步长(假设为S),然后从数列中抽第1个,第1+S个,第1+2S个,第1+3S个......数值,用插入排序算法对这些子数列进行排序。

然后我们缩短步长为M(比如令M=S/2),然后从数列中抽第1个,第1+M个,第1+2M个,第1+3M个......数值,继续用插入排序算法对这些子数列进行排序。

接着不断缩短步长,对应每个步长,都执行相同的操作,直至步长为1,此时就相当于对整个数列使用插入排序,希尔排序退化成了普通的插入排序,最后将整个数列排序完毕,但在此之前,数列已经经过了好几次的预排序,数列已经大致有序,最后再使用插入排序,就高效了很多!这里的步长,也可叫做增量,每轮排序,步长都在缩短,这就是为什么希尔排序又叫缩小增量排序的原因)

java代码实现:

public static int[] shellsort(int[] arr) {
    int len = arr.length;
    // 确定步长
    int increment = len / 2;
    while (increment > 0) {
        // 以步长increment,抽取数字
        for (int i = increment; i < len; i = i + increment) {
            // 对抽取的数字进行插入排序
            if (arr[i - increment] > arr[i]) {
                int temp = arr[i];
                int j = i - increment;
                while (j >= 0 && arr[j] > temp) {
                    arr[j + increment] = arr[j];
                    j = j - increment;
                }
                arr[j + increment] = temp;
            }
        }
        //本轮比较结束后,缩短步长
        increment = increment / 2;
    }
    return arr;
}

  • 39
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值