希尔排序原理(java实现)

来源:互联网 发布:手机更换ip地址软件 编辑:程序博客网 时间:2024/06/08 08:48

  希尔排序也是排序算法的一种,先说他的定义,希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至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;                        }                    }                }            }        }    }}

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

原创粉丝点击