1. 算法思想
希尔排序(Shell Sort),也称递减增量排序,是插入排序的一种高速而稳定的改进版本。希尔排序按其设计者希尔(Donald Shell)的名字命名,该算法由1959年公布。希尔排序是基于插入排序的如下性质而进行改进的:插入排序在对几乎已经排好序的数据操作时,效率非常高,可以达到线性排序的效率。
该方法的基本思想是:先将整个待排序列分成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上有较大提高。
假设有一个很小的数据在一个已按升序排好序的数组的末端。如果使用复杂度为O(n2)的排序(冒泡排序或插入排序)算法,可能会进行n次的比较和交换才能将该数据移至正确位置。而希尔排序会用较大的步长移动数据,所以小数据只需进行少数比较和交换即可到达正确位置。
例如,假设有一组数:[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ]。如果以步长为5开始排序,可以将这组数放在有5列的表中来更好地描述算法:
13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10
然后对每列进行排序:
10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45
这时顺序读取每行数据得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ]。这时10已经移至正确位置了,然后再以3为步长进行排序:
10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45
排序之后变为:
10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94
最后再以1为步长进行排序,即整体进行一次直接插入排序。
2. 算法实现及测试:
#include <iostream> using namespace std; // 希尔排序 void ShellSort(int data[], int count) { int step = 0; int auxiliary = 0; for (step = count / 2; step > 0; step /= 2) { // 从数组第step个元素开始 for (int i = step; i < count; i++) { // 每个元素与自己组内的数据进行直接插入排序 if (data[i] < data[i - step]) { auxiliary = data[i]; int j = i - step; while (j >= 0 && data[j] > auxiliary) { data[j + step] = data[j]; j -= step; } data[j + step] = auxiliary; } } } } int main() { int array[] = {9, 6, 3, 8, 7, 1, 5, 2, 4}; ShellSort(array, 9); for(int i = 0; i < 9; ++i) cout << array[i] << endl; return 0; }
3. 步长序列
步长的选择是希尔排序的重要部分。只要最终步长为1,任何步长序列都可以工作。算法最开始以一定的步长进行排序。然后会继续以更小的步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。
Donald Shell 最初建议步长选择为n/2,并且对步长取半直到步长达到1。虽然这样取可以比O(n2)类的算法(插入排序)更好,但仍然有减少平均时间和最差时间的余地。
已知的最好步长序列由Marcin Ciura设计:(1,4,10,23,57,132,301,701,1750,…) 这项研究也表明“在希尔排序中最主要的操作是比较,而不是交换。”用该步长序列的希尔排序比插入排序和堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。
另一个在大数组中表现优异的步长序列是(斐波那契数列除去0和1将剩余的数以黄金分割比的两倍的幂进行运算得到的数列):(1, 9, 34, 182, 836, 4025, 19001, 90358, 428481, 2034035, 9651787, 45806244, 217378076, 1031612713, …)
【学习资料】 《维基百科》 《http://blog.csdn.net/morewindows/article/details/6668714》