算法-希尔排序算法(四)

大家端午节安康,这两天都忙着玩了。没什么时间写技术博客。不过定好的计划一定要努力完成。
这次给大家介绍一下希尔排序算法,其实这是建立在插入排序之上的一种排序算法。当然,作为一个程序员,我们听到诸如:“建立在XX之上”,“是XXX的改进版”,“继XXX后,XXXX横空出世”这些句子,本能会思考旧东西的缺点,新东西的优点,新东西解决了旧东西什么问题。那么插入排序有什么问题呢?

插入排序之殇

如果仔细看过前面介绍插入排序算法的小伙伴,肯定知道插入排序是要移动元素的位置,将合适的元素插入至合适的位置。那么问题就来了,如果要对大量的数据排序,岂不是插入一次,要挪动大量的元素?插入排序在面对大量的数据时,效率十分慢。而希尔排序,就是插入排序的优化版,能在面对大量数据时也保持效率。

希尔排序定义

希尔排序(shell sort)这个排序方法又称为缩小增量排序,是1959年D·L·Shell提出来的。该方法的基本思想是:设待排序元素序列有n个元素,首先取一个整数increment(小于n)作为间隔将全部元素分为increment个子序列,所有距离为increment的元素放在同一个子序列中,在每一个子序列中分别实行直接插入排序。然后缩小间隔increment,重复上述子序列划分和排序工作。直到最后取increment=1,将所有元素放在同一个子序列中排序为止。
由于开始时,increment的取值较大,每个子序列中的元素较少,排序速度较快,到排序后期increment取值逐渐变小,子序列中元素个数逐渐增多,但由于前面工作的基础,大多数元素已经基本有序,所以排序速度仍然很快。

其实看图就比看文字更好理解:
假设我们有一个数组如下,我们第一次排序时,取间隔为4的数,那么数组便分成了下标为04,16,27,3的几组数,先对这几组分别排序。排好之后,我们再取间隔为2的数,那么数组分成了,0246与1357两组数,最后我们取间隔为1的数,这相当于一次插入排序。

在这里插入图片描述在这里插入图片描述在这里插入图片描述
注意,我们在一开始取间隔取得很大,目的就是做元素之间的快速移动,避免长距离的移动元素,随着后面间隔越来越小,但因为长距离间隔的元素已经是有序的了,所以不会存在下标第99999的需要插入到下标为2的元素位置上。

时间复杂度

灰常遗憾,希尔的时间复杂度至今仍然不确定,因为对应不通的间隔,时间复杂度是不一样的
希尔排序的复杂度和增量序列是相关的:

{1,2,4,8,…}这种序列并不是很好的增量序列,使用这个增量序列的时间复杂度(最坏情形)是O(n^2)

Hibbard提出了另一个增量序列{1,3,7,…,2^k-1},
这种序列的时间复杂度(最坏情形)为O(n^1.5)

Sedgewick提出了几种增量序列,其最坏情形运行时间为O(n^1.3),其中最好的一个序列是{1,5,19,41,109,…}

代码实现

    /**
     * 希尔排序 
     * @param arr 目标序列
     */
    public static void shellSort(int[] arr){
        int len = arr.length;
        for(int gap=len/2; gap>=1; gap=gap/2){  //拆分整个序列,元素间距为gap(也就是增量)
            //对子序列进行直接插入排序
            for(int i=gap+1; i<len; i++){
                for(int j=i-gap; j>=0&&arr[j]>arr[j+gap]; j=j-gap){        
                    swap(arr,j,j+gap);
                }
            }
        }
    }    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值