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]