希尔排序原理(java实现)

  希尔排序也是排序算法的一种,先说他的定义,希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。(摘自百度百科)
  
  看不懂,对吧,我用白话文说一说,其实他就是一个改良版的插入排序(插入排序可以参考我以前的博客),为什么这么说呢,如果你仔细去研究插入排序算法,很快就会发现,这种算法的效率与初始数据的状态有关,假如初始数据本来就是有序的,那么,排序将相当快,初始数据基本上有序时,简单的插入排序也有很高的效率,希尔排序,就是基于这个事实,设计出来的更高效的算法,他是这样的原理,首先定义一个步长(也就是增量),通过这个步长将原始序列划分成多个子序列,并将这些子序列进行简单插入排序,然后再选一个较小的步长,再将这个原始序列划分成多个子序列,再针对这些子序列进行简单插入排序,直到最后,步长不能再小了,也就是步长为1了,再进行简单插入排序之后,整个序列就变成有序序列了
  
  其实,步长为1的时候进行简单插入排序,就是真正的简单插入排序,只不过,像上面说的,这个数据的初始状态已经是基本上是有序了,所以就说,希尔排序是简单插入的改良版
  
  如果你看到这里,还是不懂的话,没关系,来举个例子,假定现在有这样一个整型数组{1,5,2,7,3,4,6,9,8,10},首先,选定一个步长,这个步长的选定是很有讲究的,不过这里我们暂且不说这个,后面我会提,就比如现在我们选定步长为3,然后,怎么就能将原始序列划分成多个数列了呢?是这样的,先把第1个数拿出来,然后,1+3,就是第4个数,1+2x3,就是第7个数,1+3x3就是第10个数,1+4x3,就是第13个数,但是,出界了,那么就不往后看了,所以,这个子序列就是{1,7,6,10},然后再拿出第2个数,2+3,就是第5个数,2+2x3就是第8个数,2+3x3就是第11个数,但是第11个数不存在,那么第二个子序列就是{5,3,9},再拿出第3个数,3+3,第6个数,3+2x3,第9个数,3+3x3,第12个数,出界,那么这个子序列就是{2,4,8},这样我们就选择出了这四个子序列,分别对这四个子序列进行简单插入排序,然后这四个序列就分别都是有序的了,原序列就变成了{1,3,2,6,5,4,7,9,8,10},读者可以自己拿张纸,自己排一下,就明白了,然后再将步数变成2,经历上面的同样的过程,最后再将步数变成1,再经历上面同样的过程,那么,整个序列就有序了,读者可以看着下面的代码,自己走一走步骤,就明白了
  
  下面是Java代码实现
  
  

class Demo
{
    public static void main(String[] args)
    {
        //定义整型数组
        int[] arr = {1,5,2,7,3,4,6,9,8,10};
        //调用希尔排序函数
        Shell(arr);
        //输出排序后的数组
        for(int i=0;i<arr.length;i++)
        {
            System.out.print(arr[i]+"   ");
        }
    }
    //定义希尔排序函数
    public static void Shell(int[] arr)
    {
        //dk是步长
        int dk = arr.length;
        while(dk!=1)
        {
            //刚开始选择长度的一半作为步长,每次减少一半
            dk = dk/2;
            //k是每个子序列的第一个元素的下标
            for(int k=0;k<=dk;k++)
            {
                //通过改变i来改变倍数,确定下标
                for(int i=1;k+i*dk<arr.length;i++)
                {
                    //j是子序列中,小于i的所有下标
                    for(int j=0;j<i;j++)
                    {
                        //子序列进行插入排序
                        if(arr[k+j*dk]>arr[k+i*dk])
                        {
                            int tmp = arr[k+i*dk];
                            for(int p=i;p>j;p--) 
                                arr[k+p*dk] = arr[k+(p-1)*dk];
                            arr[k+j*dk] = tmp;
                        }
                    }
                }
            }
        }
    }
}

  不太好理解,慢慢来,然后在这里说一下关于步长的选择问题,那是数学家研究的问题,有兴趣的读者可以去相关网站研究

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值