1.简介
希尔排序(Shell Sort),又称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
2.原理
- 选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1.
- 按增量序列个数 k,对序列进行 k 趟排序.
- 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度.
3.操作规则
- 获取增量(inc)循环
- 比较增量差值的下标数据(i = inc; i<len(array);i++ 比较[i-inc]和[inc])
- 规则交换数据
4.Golang代码
1.升序
// 希尔排序-升序
func ShellSortAsc(array []int) {
// 获取增量(increment) len(array)/2--len(array)/2/2--len(array)/2/2/2...
for inc := len(array) / 2; inc > 0; inc /= 2 {
// 假定len(array)= 10,那么inc的取值范围为:5,2,1
// 获取比较的元素的增量的下标
for i := inc; i < len(array); i++ {
// i的取值根据假定的len(array)=10,inc=5的场景下:5,6,7,8,9
temp := array[i]
// 比较inc值和i的差值的下标两个元素
for j := i - inc; j >= 0; j -= inc {
// j的取值根据假定的len(array)=10,inc=5的场景下:0,1,2,3,4
// 如果array的增量inc=5对应的下标的值:array[5],array[6],array[7],array[8],array[9]
// 小于
// array的增量inc=5的对应的下标的值:array[0],array[1],array[2],array[3],array[4]
// inc=5,i=5,j=0则让下标为0,1两个数进行有序
// inc=5,i=6,j=1则让下标为1,2两个数进行有序
// inc=5,i=7,j=2则让下标为2,3两个数进行有序
// inc=5,i=8,j=3则让下标为3,4两个数进行有序
// inc=5,i=9,j=4则让下标为4,5两个数进行有序
//=======================================
// inc=2,i=2,j=0则让下标为0,1两个数进行有序
// inc=2,i=3,j=1则让下标为1,2两个数进行有序
// inc=2,i=4,j=2则让下标为2,3两个数进行有序
// inc=2,i=5,j=3则让下标为3,4两个数进行有序
// inc=2,i=6,j=4则让下标为4,5两个数进行有序
// inc=2,i=7,j=5则让下标为5,6两个数进行有序
// inc=2,i=8,j=3则让下标为6,7两个数进行有序
// inc=2,i=9,j=7则让下标为7,8两个数进行有序
//=======================================
// inc=1,i=1,j=0则让下标为0,1两个数进行有序
// inc=1,i=2,j=1则让下标为1,2两个数进行有序
// inc=1,i=3,j=2则让下标为2,3两个数进行有序
// inc=1,i=4,j=3则让下标为3,4两个数进行有序
// inc=1,i=5,j=4则让下标为4,5两个数进行有序
// inc=1,i=6,j=5则让下标为5,6两个数进行有序
// inc=1,i=7,j=3则让下标为6,7两个数进行有序
// inc=1,i=8,j=7则让下标为7,8两个数进行有序
// inc=1,i=9,j=8则让下标为8,9两个数进行有序
if temp < array[j] {
array[j], array[j+1] = array[j+1], array[j]
} else {
break // 如果不满足,则直接退出此层循环
}
}
}
}
}
2.降序
// 希尔排序-降序
func ShellSortDesc(array []int) {
// 获取增量(increment) len(array)/2--len(array)/2/2--len(array)/2/2/2...
for inc := len(array) / 2; inc > 0; inc /= 2 {
// 假定len(array)= 10,那么inc的取值范围为:5,2,1
// 获取比较的元素的增量的下标
for i := inc; i < len(array); i++ {
// i的取值根据假定的len(array)=10,inc=5的场景下:5,6,7,8,9
temp := array[i]
// 比较inc值和i的差值的下标两个元素
for j := i - inc; j >= 0; j -= inc {
// j的取值根据假定的len(array)=10,inc=5的场景下:0,1,2,3,4
// 如果array的增量inc=5对应的下标的值:array[5],array[6],array[7],array[8],array[9]
// 小于
// array的增量inc=5的对应的下标的值:array[0],array[1],array[2],array[3],array[4]
// inc=5,i=5,j=0则让下标为0,1两个数进行有序
// inc=5,i=6,j=1则让下标为1,2两个数进行有序
// inc=5,i=7,j=2则让下标为2,3两个数进行有序
// inc=5,i=8,j=3则让下标为3,4两个数进行有序
// inc=5,i=9,j=4则让下标为4,5两个数进行有序
//=======================================
// inc=2,i=2,j=0则让下标为0,1两个数进行有序
// inc=2,i=3,j=1则让下标为1,2两个数进行有序
// inc=2,i=4,j=2则让下标为2,3两个数进行有序
// inc=2,i=5,j=3则让下标为3,4两个数进行有序
// inc=2,i=6,j=4则让下标为4,5两个数进行有序
// inc=2,i=7,j=5则让下标为5,6两个数进行有序
// inc=2,i=8,j=3则让下标为6,7两个数进行有序
// inc=2,i=9,j=7则让下标为7,8两个数进行有序
//=======================================
// inc=1,i=1,j=0则让下标为0,1两个数进行有序
// inc=1,i=2,j=1则让下标为1,2两个数进行有序
// inc=1,i=3,j=2则让下标为2,3两个数进行有序
// inc=1,i=4,j=3则让下标为3,4两个数进行有序
// inc=1,i=5,j=4则让下标为4,5两个数进行有序
// inc=1,i=6,j=5则让下标为5,6两个数进行有序
// inc=1,i=7,j=3则让下标为6,7两个数进行有序
// inc=1,i=8,j=7则让下标为7,8两个数进行有序
// inc=1,i=9,j=8则让下标为8,9两个数进行有序
if temp > array[j] {
array[j], array[j+1] = array[j+1], array[j]
} else {
break // 如果不满足,则直接退出此层循环
}
}
}
}
}
3.测试
func main() {
array := []int{1, 3, 5, 9, 10, 2, 0, 7, 8, 4}
fmt.Println("原数据:", array)
ShellSortAsc(array)
fmt.Println("希尔排序升序:", array)
ShellSortDesc(array)
fmt.Println("希尔排序降序:", array)
}
5.完整代码
package main
import "fmt"
// 希尔排序-升序
func ShellSortAsc(array []int) {
// 获取增量(increment) len(array)/2--len(array)/2/2--len(array)/2/2/2...
for inc := len(array) / 2; inc > 0; inc /= 2 {
// 假定len(array)= 10,那么inc的取值范围为:5,2,1
// 获取比较的元素的增量的下标
for i := inc; i < len(array); i++ {
// i的取值根据假定的len(array)=10,inc=5的场景下:5,6,7,8,9
temp := array[i]
// 比较inc值和i的差值的下标两个元素
for j := i - inc; j >= 0; j -= inc {
// j的取值根据假定的len(array)=10,inc=5的场景下:0,1,2,3,4
// 如果array的增量inc=5对应的下标的值:array[5],array[6],array[7],array[8],array[9]
// 小于
// array的增量inc=5的对应的下标的值:array[0],array[1],array[2],array[3],array[4]
// inc=5,i=5,j=0则让下标为0,1两个数进行有序
// inc=5,i=6,j=1则让下标为1,2两个数进行有序
// inc=5,i=7,j=2则让下标为2,3两个数进行有序
// inc=5,i=8,j=3则让下标为3,4两个数进行有序
// inc=5,i=9,j=4则让下标为4,5两个数进行有序
//=======================================
// inc=2,i=2,j=0则让下标为0,1两个数进行有序
// inc=2,i=3,j=1则让下标为1,2两个数进行有序
// inc=2,i=4,j=2则让下标为2,3两个数进行有序
// inc=2,i=5,j=3则让下标为3,4两个数进行有序
// inc=2,i=6,j=4则让下标为4,5两个数进行有序
// inc=2,i=7,j=5则让下标为5,6两个数进行有序
// inc=2,i=8,j=3则让下标为6,7两个数进行有序
// inc=2,i=9,j=7则让下标为7,8两个数进行有序
//=======================================
// inc=1,i=1,j=0则让下标为0,1两个数进行有序
// inc=1,i=2,j=1则让下标为1,2两个数进行有序
// inc=1,i=3,j=2则让下标为2,3两个数进行有序
// inc=1,i=4,j=3则让下标为3,4两个数进行有序
// inc=1,i=5,j=4则让下标为4,5两个数进行有序
// inc=1,i=6,j=5则让下标为5,6两个数进行有序
// inc=1,i=7,j=3则让下标为6,7两个数进行有序
// inc=1,i=8,j=7则让下标为7,8两个数进行有序
// inc=1,i=9,j=8则让下标为8,9两个数进行有序
if temp < array[j] {
array[j], array[j+1] = array[j+1], array[j]
} else {
break // 如果不满足,则直接退出此层循环
}
}
}
}
}
// 希尔排序-降序
func ShellSortDesc(array []int) {
// 获取增量(increment) len(array)/2--len(array)/2/2--len(array)/2/2/2...
for inc := len(array) / 2; inc > 0; inc /= 2 {
// 假定len(array)= 10,那么inc的取值范围为:5,2,1
// 获取比较的元素的增量的下标
for i := inc; i < len(array); i++ {
// i的取值根据假定的len(array)=10,inc=5的场景下:5,6,7,8,9
temp := array[i]
// 比较inc值和i的差值的下标两个元素
for j := i - inc; j >= 0; j -= inc {
// j的取值根据假定的len(array)=10,inc=5的场景下:0,1,2,3,4
// 如果array的增量inc=5对应的下标的值:array[5],array[6],array[7],array[8],array[9]
// 小于
// array的增量inc=5的对应的下标的值:array[0],array[1],array[2],array[3],array[4]
// inc=5,i=5,j=0则让下标为0,1两个数进行有序
// inc=5,i=6,j=1则让下标为1,2两个数进行有序
// inc=5,i=7,j=2则让下标为2,3两个数进行有序
// inc=5,i=8,j=3则让下标为3,4两个数进行有序
// inc=5,i=9,j=4则让下标为4,5两个数进行有序
//=======================================
// inc=2,i=2,j=0则让下标为0,1两个数进行有序
// inc=2,i=3,j=1则让下标为1,2两个数进行有序
// inc=2,i=4,j=2则让下标为2,3两个数进行有序
// inc=2,i=5,j=3则让下标为3,4两个数进行有序
// inc=2,i=6,j=4则让下标为4,5两个数进行有序
// inc=2,i=7,j=5则让下标为5,6两个数进行有序
// inc=2,i=8,j=3则让下标为6,7两个数进行有序
// inc=2,i=9,j=7则让下标为7,8两个数进行有序
//=======================================
// inc=1,i=1,j=0则让下标为0,1两个数进行有序
// inc=1,i=2,j=1则让下标为1,2两个数进行有序
// inc=1,i=3,j=2则让下标为2,3两个数进行有序
// inc=1,i=4,j=3则让下标为3,4两个数进行有序
// inc=1,i=5,j=4则让下标为4,5两个数进行有序
// inc=1,i=6,j=5则让下标为5,6两个数进行有序
// inc=1,i=7,j=3则让下标为6,7两个数进行有序
// inc=1,i=8,j=7则让下标为7,8两个数进行有序
// inc=1,i=9,j=8则让下标为8,9两个数进行有序
if temp > array[j] {
array[j], array[j+1] = array[j+1], array[j]
} else {
break // 如果不满足,则直接退出此层循环
}
}
}
}
}
func main() {
array := []int{1, 3, 5, 9, 10, 2, 0, 7, 8, 4}
fmt.Println("原数据:", array)
ShellSortAsc(array)
fmt.Println("希尔排序升序:", array)
ShellSortDesc(array)
fmt.Println("希尔排序降序:", array)
}
原数据: [1 3 5 9 10 2 0 7 8 4]
希尔排序升序: [0 1 2 3 4 5 7 8 9 10]
希尔排序降序: [10 9 8 7 5 4 3 2 1 0]