排序进阶——希尔排序(算法二)

Posted 可乐

tags:

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

提升效率的本质在于少做事。

一. 序

之前介绍的入门排序方法,复杂度都是O()以这种复杂度去对大量数据排序显然是不可行的。即便是应付面试,也不太可能用冒泡排序、选择排序以及插入排序蒙混过关。


我们知道,插入排序的优点是针对比较有序的数据进行排序是相当高效的,缺点则是每次只移动一个数据。接下来,我们就针对插入排序的缺点,对其进行优化。


二. 插入排序回顾

首先看一下插入排序的实现,以数据7、8、3、5为例:

  1. 取第一个数7,肯定是有序的,不需要处理,得到7、8、3、5

  2. 取第二个数8,比7大放在7后面,得到7、8、3、5

  3. 取第三个数字3,分别与8、7比较,得到3、7、8、5

  4. 最后取5,分别与8、7、3相比,得到3、5、7、8


不难发现,几乎每个数字之间都做了比较。效率本身除了做事的速度,还取决于做事的量。想要更快的完成排序,计算机的速度可以看成是常量,可以优化的在于我们如何指导计算机少做事。


插入排序的优点是对基本有序的数据排序效率高,这给我们的启发便是想办法让一个比较无序的数组先变得比较有序。插入排序的缺点是一次只移动一个数据,优化的方向显然就是一次移动多个数据。


三. 希尔排序

由此,插入排序的进阶版本,希尔排序(Shell sort)被发明了出来。还是外国人的老套路,该算法以设计者希尔(Donald Shell)的名字命名,于1959年公布。


希尔排序首先把一串数据按照一定的间隔(Gap)分开,比如7、8、3、5按照间隔2分开,就变成了两个数组7、3和8、5,这样可以分别对这两个小的数组进行排序,变成3、7和5、8。放在原来的数组中看就变成了3、5、7、8。最后以1的间隔扫描一遍数据,不需要再移动任何数据。



一次搞定,牛叉不牛叉,哇塞不哇塞。


到此可以看出,希尔排序通过把数据按照一定的间隔分组,然后以小组为单位,在小组内使用插入排序,然后逐步缩小分组间隔,对于100个数据A1~A100,可以先按照50为间隔分成:

  • A1、A51

  • A2、A52

  • ……

  • A50、A100

等50组,每组先进行插入排序。然后再以25为间隔,把数据分成25组,每组4个数据进行插入排序。以此类推,直到最后以1为间隔分成1个组,再做一次插入排序。


要注意的是,分组间隔里面间隔1是必选项,由它保证整个数据最后肯定是有序的。其余间隔如何选择是个很复杂的数学问题,简单的实现可以用待排序数据的个数不停除以2,直到最后间隔为1停止。


老规矩,算法一般来说与编程语言无关,因此这里依然用通俗易懂的伪码(Pseudocode):

gaps = [701, 301, 132, 57, 23, 10, 4, 1]foreach (gap in gaps){      for (i = gap; i < n; i += 1)   {              temp = a[i]             for (j = i; j >= gap and a[j - gap] > temp; j -= gap)       {           a[j] = a[j - gap]       }             a[j] = temp   }}


四. 复杂度

希尔排序的时间复杂度是多少呢?不知道,我是认真的,确实不知道。希尔排序使用的分组间隔如果很小,分出来的组就少,每个组内需要比较的元素就很多;反之,如果间隔很大,每个组内需要比较的元素大幅减少,但是需要比较的组却大幅增加。很容易想到,分组间隔需要找到一个均衡。目前Sedgewick提出的(1, 5, 19, 41, 109,...)被认为是最好的分组间隔。该序列的项来自:

排序进阶——希尔排序(算法二)

排序进阶——希尔排序(算法二)

使用此序列,在小数组中比快速排序和堆排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。目前一般认为希尔排序的时间复杂度在O(n^(1.3~2))之间。由于希尔排序的复杂度与排序分组间隔的选择直接相关,目前还是个未解决问题(Open problem)。


说到排序,一般还会提到排序的稳定性。什么是稳定性呢?简单的讲,就是相同数据之间的相对位置是否会多次变动,如果会多次变动,就是不稳定的,否则就是稳定的。不难看出,希尔排序会使用不同的间隔多次排序,很可能多次移动同一数据,因此是不稳定的。


简单看一下插入排序和希尔排序的效率,以10000个随机数排序耗时为例:



耗时差了近200倍,这就是算法的魅力。有兴趣后台回复希尔排序』获取源码。


五. 小结分析

希尔排序虽然不是速度最快的排序算法,但是希尔排序的应用极其广泛。原因主要有如下几点:

  • 排序速度比较快,比插入排序等O()的算法要好。

  • 代码实现极其简单,且空间复杂度为O(1),排序过程仅需一个辅助存储变量。

  • 虽然大部分情况下没有快速排序速度快,但是希尔排序在程序实现上不需要开栈操作,使用的空间极少,而快速排序则需要开辟大量的栈空间。


PS:加了底部广告,就不开赞赏了


推荐:

推荐阅读:

后台回复希尔排序』获取排序源码。

喜欢就关注』或者『分享』吧。

以上是关于排序进阶——希尔排序(算法二)的主要内容,如果未能解决你的问题,请参考以下文章

《算法零基础100讲》(第38讲) 排序进阶 - 希尔排序

排序算法二(归并排序快速排序希尔排序)

希尔排序

排序算法——希尔排序的图解代码实现以及时间复杂度分析

七大排序算法(插排,希尔,选择排序,堆排,冒泡,快排,归并)--图文详解

排序算法之希尔排序