1959 年 7 月,美国辛辛那提大学的数学系博士 Donald Shell 在 《ACM 通讯》上发表了希尔排序算法,成为首批将时间复杂度降到 O(n²)以下的算法之一。虽然原始的希尔排序最坏时间复杂度仍然是 O(n²) ,但经过优化的希尔排序可以达到 O(n1.3)甚至O(n7/6)。
略为遗憾的是,所谓「一将功成万骨枯」,希尔排序和冒泡、选择、插入等排序算法一样,逐渐被快速排序所淘汰,但作为承上启下的算法,不可否认的是,希尔排序身上始终闪耀着算法之美。
希尔排序本质上是对插入排序的一种优化,它利用了插入排序的简单,又克服了插入排序每次只交换相邻两个元素的缺点。它的基本思想是:
举个例子,对数组 [84,83,88,87,61,50,70,60,80,99] 进行希尔排序的过程如下:
第一遍(5 间隔排序):按照间隔 5 分割子数组,共分成五组,分别是
[84,50],[83,70],[88,60],[87,80],[61,99]。对它们进行插入排序,排序后它们分别变成:
[50,84],[70,83],[60,88],[80,87],[61,99],此时整个数组变成 [50,70,60,80,61,84,83,88,87,99]
第二遍(2 间隔排序):按照间隔 2 分割子数组,共分成两组,分别是
[50,60,61,83,87],[70,80,84,88,99]。对他们进行插入排序,排序后它们分别变成:[50,60,61,83,87],[70,80,84,88,99],此时整个数组变成 [50,70,60,80,61,84,83,88,87,99]。这里有一个非常重要的性质:当我们完成 2 间隔排序后,这个数组仍然是保持 5 间隔有序的。也就是说,更小间隔的排序没有把上一步的结果变坏。
第三遍(1 间隔排序,等于直接插入排序):按照间隔 1 分割子数组,分成一组,也就是整个数组。对其进行插入排序,经过前两遍排序,数组已经基本有序了,所以这一步只需经过少量交换即可完成排序。排序后数组变成 [50,60,61,70,80,83,84,87,88,99],整个排序完成。