也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率;
- 插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位;
基础是插入排序,我们先看图,图片动态展示:
这个图太快了还是不知道他在干嘛,在给一张图(图片均来自互联网):
希尔排序中步长的选择是重中之重!【来自于维基百科】
-
最终步长必须为1,任何步长串行都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。
-
初始步长选择:Donald Shell 最初建议步长选择为\frac{n}{2}并且对步长取半直到步长达到 1。虽然这样取可以比\mathcal{O}(n^2)类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。
希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。
已知的最好步长串行是由Sedgewick提出的 (1, 5, 19, 41, 109,...),该串行的项来自 9 * 4^i - 9 * 2^i + 1 和 4^i - 3 * 2^i + 1 这两个算式。这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换”。用这样步长串行的希尔排序比插入排序和堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。
另一个在大数组中表现优异的步长串行是(斐波那契数列除去0和1将剩余的数以黄金分区比的两倍的幂进行运算得到的数列):(1, 9, 34, 182, 836, 4025, 19001, 90358, 428481, 2034035, 9651787, 45806244, 217378076, 1031612713, …)
如图2。步长为3时,我们把数据分组为:a[1], a[4], a[7]与a[2], a[5], a[8]与a[3], a[6], a[9],我们分别对这三组进行插入排序;
步长为2时,我们继续分组为:a[1], a[3], a[5], a[7], a[9]与a[2], a[4], a[6], a[8],我们分别对这两组排序;
步长为1时,进行真正的插入排序,但由于大量数据以有序,所以实际时间复杂度会小于原始的插入排序。