datatable的数据进行组内排序_排序进阶:希尔排序

30d372f3b41b82e09f0384c6666323d8.png

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

一. 序

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

二. 插入排序回顾

首先看一下插入排序的实现,以数据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的间隔扫描一遍数据,不需要再移动任何数据。

16f67a14d19a08a37a1228c79c3a94b8.png

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

到此可以看出,希尔排序通过把数据按照一定的间隔分组,然后以小组为单位,在小组内使用插入排序,然后逐步缩小分组间隔,对于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,...)被认为是最好的分组间隔。 该序列的项来自:

5ead2a274f2942f5955c147089db7ca6.png
d4cf2214b78955734ceca8b65b7d859b.png

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

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

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

f3dbd30dc3f6a55effd17dfc50a17bff.png

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

五. 小结分析

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

  • 排序速度比较快,比插入排序等O( n² )的算法要好。
  • 代码实现极其简单,且空间复杂度为O(1),排序过程仅需一个辅助存储变量。
  • 虽然大部分情况下没有快速排序速度快,但是希尔排序在程序实现上不需要开栈操作,使用的空间极少,而快速排序则需要开辟大量的栈空间。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值