希尔排序 #算法学习

本文详细介绍了希尔排序的原理及其优化,包括希尔排序的插入排序基础、Hibbard增量和Sedgewick增量的计算公式,并提供了相应的Go语言实现。通过实际运行比较,展示了不同增量序列对排序速度的影响,证明了优化后的希尔排序在效率上的提升。
摘要由CSDN通过智能技术生成

每日一题
Day1 兔子试毒 #每日一题
Day2 排序算法-插入排序 #每日一题
Day3 排序算法 #每日一题


希尔排序

希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。

数组准备

Day2 排序算法-插入排序 #每日一题

默写排序算法

func arrSort(arr []int) []int {
    length := len(arr)
    for step := length / 2; step >= 1; step /= 2 {
        for i := step; i < length; i++ {
            current := arr[i]
            j := i - step
            for j >= 0 && arr[j] > current; j -= step {
                arr[j+step] = arr[j]
            }
            arr[j+step] = current
        }
    }
    return arr
}

输出

start: 1630316402432926700
排序前: [793274 498081 266786 151008 636829 243626 651548 305886 697888 831901] ... [715529 760583 152069 297222 979203 168585 95815 653064 187794 350723]
排序后: [8 20 31 33 34 40 44 49 61 69] ... [999912 999938 999939 999947 999955 999957 999964 999984 999986 999994]
end: 1630316403232122200
duration: 799195500

耗时0.79秒,果然比插入算法还要快很多

理解

刚看到希尔排序的时候感觉不是很好理解,看了很多帖子,其中这个帖子讲的比较详细

扩展

希尔算法又称“缩小增量排序”

Hibbard增量和Sedgewick增量

原始希尔算法的步长计算公式为 Dk = len(arr) / 2
Hibbard增量步长计算公式为 Dk = 2^k-1

func hbd(length int) (hibbard []int) {
    for i := 1; ; i++ {
        step := int(math.Pow(2, float64(i)) - 1)
        if step < length {
            hibbard = append(hibbard, step)
        } else {
            break
        }
    }
    return
}
func arrSort(arr []int) []int {
    length := len(arr)
    steps := hbd(length)
    // fmt.Println(steps)
    sl := len(steps)
    for s := sl - 1; s >= 0; s-- {
        step := steps[s]
        for i := step; i < length; i++ {
            current := arr[i]
            j := i - step
            for ; j >= 0 && arr[j] > current; j -= step {
                arr[j+step] = arr[j]
            }
            arr[j+step] = current
        }
    }
    return arr
}
start: 1630317181790944800
排序前: [793274 498081 266786 151008 636829 243626 651548 305886 697888 831901] ... [715529 760583 152069 297222 979203 168585 95815 653064 187794 350723]
排序后: [8 20 31 33 34 40 44 49 61 69] ... [999912 999938 999939 999947 999955 999957 999964 999984 999986 999994]
end: 1630317182590263900
duration: 799319100

Sedgewick增量步长计算公式为 Dk = 9*4^k - 9*2^k + 1 || 4^k - 3*2^k + 1

func sgw1(i int) int {
    return int(9*math.Pow(4, float64(i)) - 9*math.Pow(2, float64(i)) + 1)
}
func sgw2(i int) int {
    return int(math.Pow(4, float64(i)) - 3*math.Pow(2, float64(i)) + 1)
}
func sgw(length int) (sedgewick []int) {
    i := 0
    j := 0
    for len(sedgewick) == 0 || sedgewick[len(sedgewick)-1] < length {
        step1 := sgw1(i)
        for ; ; j++ {
            step2 := sgw2(j)
            if step1 > step2 {
                if step2 > 0 && step2 < length {
                    sedgewick = append(sedgewick, step2)
                }
            } else {
                break
            }
        }
        if step1 < length {
            sedgewick = append(sedgewick, step1)
            i++
        } else {
            break
        }
    }
    return
}
func arrSort(arr []int) []int {
    length := len(arr)
    steps := sgw(length)
    // fmt.Println(steps)
    sl := len(steps)
    for s := sl - 1; s >= 0; s-- {
        step := steps[s]
        for i := step; i < length; i++ {
            current := arr[i]
            j := i - step
            for ; j >= 0 && arr[j] > current; j -= step {
                arr[j+step] = arr[j]
            }
            arr[j+step] = current
        }
    }
    return arr
}
start: 1630316482425062200
排序前: [793274 498081 266786 151008 636829 243626 651548 305886 697888 831901] ... [715529 760583 152069 297222 979203 168585 95815 653064 187794 350723]
排序后: [8 20 31 33 34 40 44 49 61 69] ... [999912 999938 999939 999947 999955 999957 999964 999984 999986 999994]
end: 1630316483222124000
duration: 797061800
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值