【排序算法 6】希尔排序
希尔排序(插入排序)
显然,简单插入排序的过程虽然简单,但是效率上并不高,在较小的数据上可能还能接受,所以根据插入排序的特性,有一个高效的优化版本,也就是希尔排序。
【算法介绍】
不多说,上图(受限于帧数,所以有些移动过程可能相较简单插入排序的动画演示要简化一些):
仔细观察过程,不难发现还是简单插入排序的思想:
每次分成多组,每组的第1个之间进行排序,第2个之间进行排序,第3个之间进行排序……随着每组数据个数的减少,数据越来越趋于有序,而最后1次则是1个数字1组,也就是完全的简单插入排序,但是由于之前的排序过程已经使序列大致有序,最后一轮事实上速度是很快的。
【代码实现】
注意到对于样例数列,一开始是4个数字一组,接下来是2个数字一组,最后是一个数字一组,不难发现是采取类似对分的方式。假设变量h表示每一组的个数,那么h将不断除以2,表示分组不断减小,而当h变为1时,则是最后一轮排序。
def sort(a :[]):
#insert表示将x从pos开始,以step为分隔向前插入
def insert(x:int, pos:int, step:int):
while pos > -1 and x < a[pos]:
a[pos+step] = a[pos]
pos -= step
a[pos+step] = x
#h表示每组的数据个数
n = len(a)
h = n//2
while h>0:
for i in range(0, n, h): #以h为间隔进行简单插入排序
insert(a[i], i-h, h)
h //= 2 #更新分组
return a
【效率分析】
希尔排序的效率一直是个迷,通常期望是O(NlogN)的,较为官方的说法是O(n^(1.3~2))。事实上,希尔排序的h未必要进行二分,我们只需令h从一个初始值不断变小,最后为1,一定可以完成排序。
所以寻找一个h变化的序列才是希尔排序效率的关键。不少论文研究了各种不同的递增序列,基本是研究h序列各个元素之间的数学关系,但没有有效地证明某个序列是最优的。目前已知较优的一个序列是1、4、13、40、121、364、1093……,即h[i] = h[i-1]*3+1,所以大家可能会看到有些希尔排序的h不是除以2而是除以3-1的。当然效率上并不会有太大的差距。