排序算法_希尔排序
一、算法描述
- 先取一个小于n的整数d1作为第一个增量,把全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。
- 先在各组内进行直接插人排序;
- 取第二个增量d2<d1重复上述的分组和排序,
- 直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
二、图示
待排序数组[13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10],如果我们以步长为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步长进行排序(此时就是简单的插入排序了)。
三、性能描述
数据结构 :数组
最差时间复杂度 :O(nlog2n)
最优时间复杂度 :O(n)
平均时间复杂度 :根据步长序列的不同而不同
最差空间复杂度 :总共O(n)
四、总结
关键在于步长序列的选择:
已知的最好步长序列由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, …)
五、C语言实现代码
1 #include <stdio.h> 2 3 int main() 4 { 5 const int n = 5; 6 int i, j, temp; 7 int gap = 0; 8 int a[] = {5, 4, 3, 2, 1}; 9 while (gap<=n) 10 { 11 gap = gap * 3 + 1; 12 } 13 while (gap > 0) 14 { 15 for ( i = gap; i < n; i++ ) 16 { 17 j = i - gap; 18 temp = a[i]; 19 while (( j >= 0 ) && ( a[j] > temp )) 20 { 21 a[j + gap] = a[j]; 22 j = j - gap; 23 } 24 a[j + gap] = temp; 25 } 26 gap = ( gap - 1 ) / 3; 27 } 28 }
参考文档: