面试之希尔排序

Posted 每日一算法

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试之希尔排序相关的知识,希望对你有一定的参考价值。

1
题目


通过代码实现希尔排序算法。



2
解答


希尔排序(shell sort)这个排序方法又称为缩小增量排序,是1959年D·L·Shell提出来的,该方法的基本思想是:设等待排序元素序列有n个元素,首先取一个整数increment(小于n)作为间隔将全部元素分为n/increment个子序列,所有距离为increment的元素放在同一个子序列中,在每一个子序列中分别实行直接插入排序。然后缩小间隔increment,重复上述子序列划分和排序工作。直到最后取increment=1,将所有元素放在同一个子序列中排序为止。 


由于开始时,increment的取值较大,每个子序列中的元素较少,排序速度较快,到排序后期increment取值逐渐变小,子序列中元素个数逐渐增多,但由于前面工作的基础,大多数元素已经基本有序,所以排序速度仍然很快。


增量increment的取法有各种方案,最初shell提出取increment=n/2向下取整,increment=increment/2向下取整,直到increment=1。但由于直到最后一步,在奇数位置的元素才会与偶数位置的元素进行比较,这样使用这个序列的效率会很低。后来Knuth提出取increment=n/3向下取整+1.还有人提出都取奇数为好,也有人提出increment互质为好。应用不同的序列会使希尔排序算法的性能有很大的差异。


下面我们来举个例子,来说明希尔排序的过程。

比如有{49,38,65,97,76,13,27,78,34,12,31}


因为总共有11个元素,所以increment=11/2=5。
increment=5的时候
第一个循环第一次是第一位和第六位比较,因为49>13,所以交换位置
49    38   65   97   76    13    27   78   34   12   31
13     38   65   97   76    49    27  78   34   12   31  


第一个循环第二次是第二位和第七位比较,因为38>27,所以交换位置
13     38   65   97   76   49   27   78   34   12   31 
13    27    65   97   76   49    38    78   34  12   31  


第一个循环第三次是第三位和第八位比较,因为78>65,所以不交换位置
13    27   65    97   76   49   38    78    34  12   31  
13    27    65    97   76   49   38    78    34   12   31  


第一个循环第四次是第四位和第九位比较,因为97>34,所以交换位置
13    27   65    97    76   49   38   78    34    12   31  
13    27   65    34    76   49   38   78    97    12   31  


第一个循环第五次是第五位和第十位比较,因为76>12,所以交换位置
13    27    65   34    76    49   38   78   97    12    31  
13    27   65   34   12    49    38   78   97    76   31  


第一个循环第六次是第六位和第十一位比较,因为31<49,所以交换位置
13    27    65   34   12   49     38   78   97   76  31   
13   27    65   34   12    31     38    78   97   76  49   


到此increment=5时的排序结束


然后increment=increment/2=2。
第二个循环第一次是第一位和第三位比较,因为65>13,所以不交换位置
13    27     65    34    12   31    38    78   97   76  49   
13    27    65    34   12   31    38    78   97   76  49  


第二个循环第二次是第二位和第四位比较,通过while循环,因为34>27,所以不交换位置
13    27    65     34    12   31    38    78   97   76  49 
13   27    65    34    12   31    38    78   97   76  49


第二个循环第三次,首先第三位和第五位比较,因为12<65,交换位置,再次第一位和第三位比较,因为13>12,所以交换位置。
13    27    65    34   12    31    38    78   97   76  49 
12    27    13     34    65   31    38    78   97   76  49


第二个循环第四次循环,首先第四位和第六位比较,因为31<34,交换,再次第二位和第四位比较,因为31>27,所以不交换位置。
12    27    13    34    65     31    38    78   9 7   76  49 
12    27    13    31     65    34   38    78   97   76  49


第二个循环第五次是首先是第五位和第七位比较,因为38<65,所以交换位置,再次比较38>13, 因为不交换,说明当前步长的位置(1,3,5,7)已经顺序正确, 退出循环。
12    27    13     31    65    34    38    78   97   76  49
12    27    13     31    38    34    65    78   97   76  49


第二个循环第六次是比较第六个和第八个数,因为34<78,所以不交换,退出循环。
12   27   13     31     38    34    65     78   97   76  49
12   27   13    31    38    34    65    78    97   76  49


第二个循环第七次循环,从后往前比较下面红色的数字,可以得到以下的结果
12   27   13    31    38   34    65     78    97    76  49
12   27   13    31    38   34    65    78    97   76   49

第二个循环第八次是通过while循环,从后往前比较下面红色的数字,可以得到以下的结果
1 2   27   13    31    38     34    65    78    97    76   49
12   27   13    31    38   34    65    76    97     78   49


第二个循环第九次是第九个和第十一个比较,因为97>49,所以交换位置,再次比较49<65,所以也需要交换位置, 再次比较49>38,不交换位置,退出循环。
12   27   13     31    38    34    65     76    97     78   49
12   27   13    31    38    34    49     76    65    78    97


到此increment=2时的排序结束


然后increment=increment/2=1。
第三个循环第一次是通过比较第一个和第二个数,因为12<27,所以不交换。
12   27    13    31    38   34   49    76   65   78   97
12   27    13    31    38   34   49    76   65   78   97


第三个循环第二次是通过比较第二个和第三个数,因为13<27,所以交换,再次比较12和13,因为12<13,不交换,所以退出循环。
12    27   13     31    38   34   49    76   65   78   97
12    13   27     31    38   34   49    76   65   78   97


第三个循环第三次是通过比较第三个和第四个数,因为31>27,所以不交换。
12   13     27    3   38   34   49    76   65   78   97
12   13    27    31     38   34   49    76   65   78   97


第三个循环第四次是通过比较第四个和第五个数,因为31<38,所以不交换。
12   13    27     31    38    34   49    76   65   78   97
12   13    27     31    38   34   49    76   65   78   97


以此类推...
12   13    27    31    34    38    49   76   65   78   97
12   13    27    31    34    38   49    76   65   78   97
12   13    27    31    34    38    49   76    65   78   97
12   13    27    31    34    38    49    65   76    78   97
12   13    27    31    34    38   49   65   76   78    97
12   13    27    31    34    38   49   65   76    78   97


那么上面的排序方法是否稳定的呢?首先来了解下稳定性的概念


通俗地讲就是能保证排序前两个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。在简单形式化一下,如果Ai = Aj,Ai原来在位置前,排序后Ai还是要在Aj位置前。


从上面概念可以看到,希尔排序,两个相同的数,在排序的过程中会发生交换,所以希尔排序是一种不稳定的排序算法。


希尔排序的时间复杂度是NlogN,他和直接排序的区别是:

a)直接插入排序是稳定的;而希尔排序是不稳定的。

b)直接插入排序更适合于原始记录基本有序的集合。

c)希尔排序的比较次数和移动次数都要比直接插入排序少,当 N 越大时,效果越明显。

d)在希尔排序中,增量序列 increment 的取法最后一个步长必须是 1 。



3
代码



https://github.com/1260380285/suanfa/blob/yuanbing/src/com/ShellPaixun.java



你的关注是我最大的动力

如果你想要跟大家分享你的文章,欢迎留言投稿~

如果你喜欢,请留下你的赞哦


以上是关于面试之希尔排序的主要内容,如果未能解决你的问题,请参考以下文章

《糊涂算法》之八大排序——希尔排序

算法精讲——排序算法之希尔排序

面试官:手写一个希尔排序,并对其改进

经典排序之希尔排序

排序算法之希尔排序

排序算法之希尔排序