希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。
取自维基百科中的例子:
例如,假设有这样一组数[ 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步长进行排序(此时就是简单的插入排序了)。
代码实现:
package main
import "fmt"
func main() {
arr := []int{13, 14, 94, 33, 82, 25, 59, 94, 65, 23, 45, 27, 73, 25, 39, 10}
shellSort(arr, len(arr)/2)
fmt.Println(arr)
}
/**
希尔排序:把切片分成n个batch,对每个batch进行插入排序;然后减小batch,再对每个batch进行插入排序;直到bathc等于1
*/
func shellSort(arr []int, batchSize int) {
if batchSize < 1 {
return
}
// k : 每个batch中的元素所在batch的index, 介于[0, batchSize)
for k := 0; k < batchSize; k++ {
// 用到了插入排序
for j := 1; batchSize*j+k < len(arr); j++ { // j: 用来获取每个batch所在的第k个元素,拥有多少个batch
for n := j; n > 0; n-- {
pre := batchSize*(n-1) + k
next := batchSize*n + k
if arr[next] < arr[pre] {
arr[next], arr[pre] = arr[pre], arr[next]
}
}
}
}
shellSort(arr, batchSize/2)
}
原始的算法实现在最坏的情况下需要进行O(n2)的比较和交换。V. Pratt对算法进行了少量修改,可以使得性能提升至O(n log2 n)。这比最好的比较算法的O(n log n)要差一些。
希尔排序是一种改进的插入排序算法,通过分组减少元素移动次数提高效率。它先用较大的步长进行排序,逐步减小步长直到1,最后进行插入排序。Golang实现的希尔排序在最坏情况下时间复杂度为O(n^2),Pratt的修改版可提升至O(n log2 n)。
152

被折叠的 条评论
为什么被折叠?



