|
楼主 |
发表于 2013-4-20 13:42
|
显示全部楼层
本帖最后由 lee1892 于 2013-4-24 14:36 编辑
希尔排序是插入排序的一个优化。在插入排序中,每次对比是由后前逐个对比,或言对比的步长为1。有个叫Donald Shell的家伙提出,对比的步长可由大至小,直至步长为1变为插入排序。这样一来在最初的几个对比步长中,较小的元素(假设按升序排序)就会向目标位置前进一大步。
运作方式:
1、设置步长序列,由大至小。
2、由步长序列中,逐个获取步长。
3、由源数据中第步长+1个元素向后扫描,作为基准值。
4、由步骤3中的基准值元素向前扫描与基准值对比,并进行必要的位移,同时每次递减为步长而不是1。
5、将基准值插入到正确的位置。
6、重复2、3、4、5,直至步长为1。
插入排序 | 希尔排序 | [code=vb]Sub InsertionSort(ByRef arr)
Dim i&, j&, vTemp
For i = 2 To UBound(arr)
vTemp = arr(i)
For j = i To 2 Step -1
If arr(j - 1) < vTemp Then Exit For
arr(j) = arr(j-1)
Next
arr(j) = vTemp
Next
End Sub[/code] | [code=vb]Sub ShellSort(ByRef arr)
Dim i&, j&, vTemp, aGaps, nGap, nLen&
aGaps = Array(701, 301, 132, 57, 23, 10, 4, 1)
nLen = UBound(arr)
For Each nGap In aGaps
For i = nGap + 1 To nLen
vTemp = arr(i)
For j = i To nGap + 1 Step nGap * -1
If arr(j - nGap) < vTemp Then Exit For
arr(j) = arr(j - nGap)
Next
arr(j) = nTemp
Next
Next
End Sub[/code] |
希尔排序的可视化图:
最初Shell提出的步长序列是 k = n/2,即由数据长度的一半开始,每次减半,但很快就被证明是个非常不怎么样的序列。以下是一些已经被证明非常好的步长序列:
公式 | 序列数值 | 最坏情况的时间复杂度 | 作者/年份 | 9 * [4 ^ (k - 1) - 2 ^ (k - 1)] + 1
4 ^ (k + 1) - 6 * 2 ^ k + 1 | 1, 5, 19, 41, 109, ... | O[n ^ (4/3)] | Sedgewick/1986 | 4 ^ k + 3 * 2 ^ (k - 1) + 1 | 1, 8, 23, 77, 281, ... | O[n ^ (4/3)] | Sedgewick/1986 | INT{(9 ^ k - 4 ^ k) / [ 5 * 4 ^ (k - 1)]} + 1 | 1, 4, 9, 20, 46, 103, ... | 未知 | Tokuda/1992 | 未知 | 1, 4, 10, 23, 57, 132, 301, 701 | 未知 | Ciura/2001 | 费波那契数列除去0和1将剩余的数
以黄金分区比的两倍的幂进行运算得到的数列 | 1, 9, 34, 182, 836, 4025, 19001, ... | 未知 | 在大数组中有优异表现 |
值得指出的是,希尔排序通常只在数量较小的数组中表现较好,但通常的对于大量数据而言希尔排序比快速排序慢。
|
|