希尔排序法优化

希尔排序法的代码实现:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    times := int64(time.Now().Nanosecond())
    rand.Seed(times)
    l := 100000
    list := make([]int, l)
    for i := 0; i < l; i++ {
        list[i] = rand.Intn(l)
    }
    start := time.Now()
    ShellSort(list)
    end := time.Now()
    dur := end.Sub(start)
    fmt.Println(dur) // 显示消耗的时间
}

// 希尔排序函数
func ShellSort(list []int) {
    iLen := len(list)
    for i := 1; i < iLen; i++ {
        d := (iLen - 1) / i
        for j := 0; j+d < iLen; j++ {
            if list[j] > list[j+d] {
                list[j], list[j+d] = list[j+d], list[j]
            }
        }
    }
}

Output:
command-line-arguments
24.0993784s

经过多次测试,10万个随机数排序所需要的时间基本都维持在25秒左右(原谅我的笔记本比较旧,跟随我多年了)。
如果在 d 每次赋值后,把 d 的值打印出来,如下面这样:

d := (iLen - 1) / i
fmt.Printf("%d, ", d)

可以发现 d 从某个值开始会出现重复,而且每个值重复的次数会越来越多。这就会造成非常多的重复操作,而这些操作还套着一重循环,这浪费了大量的执行时间。
发现问题,就可以解决问题。解决的办法就是在 d 出现重复时记录 d 的值,中止当前循环,进入到另一个从 d-1 到 1 的循环,来完成后面的排序,这样就可以有效的避免因 d 值重复在产生的大量重复操作。具体代码如下:

func ShellSort(list []int) {
    iLen := len(list)

    iMark := 0

    for i := 1; i < iLen; i++ {
        d := (iLen - 1) / i

        if d == iMark { // 当 d 开始出现重复,则后面的都会重复而且重复次数越来越多,应该跳出该循环由后面的代码完成排序
            break
        }

        for j := 0; j+d < iLen; j++ {
            if list[j] > list[j+d] {
                list[j], list[j+d] = list[j+d], list[j]
                countSh++
            }
        }

        iMark = d
    }

    // 此处代替重复循环,可减少大量无用的循环判断
    for d := iMark - 1; d > 0; d-- {
        for j := 0; j+d < iLen; j++ {
            if list[j] > list[j+d] {
                list[j], list[j+d] = list[j+d], list[j]
                countSh++
            }
        }
    }
}

测试结果如下:

Output:
command-line-arguments
349.0199ms

经过多次测试显示,同样10万个随机数进行排序,运行时间都维持在350毫秒到400毫秒之间,优化的效果还是非常明显的。

然后,还有一种写法,效率最好,代码如下:

func ShellSort2(list []int) {
    iLen := len(list)
    for d := iLen / 2; d > 0; d /= 2 {
        for i := d; i < iLen; i++ {
            for j := i; j-d >= 0 && list[j-d] > list[j]; j -= d {
                list[j-d], list[j] = list[j], list[j-d]
            }
        }
    }
}

Output:
command-line-arguments
43.0025ms

同样10万个随机数排序,只需要45毫秒左右。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值