Go语言map传值拷贝问题解决方案:优化Collatz序列记忆化搜索性能
Go求解Collatz最长序列性能优化方案
求解Project Euler第14题时,暴力解法耗时0.5秒,引入记忆化搜索优化后仅提升到0.36秒,远低于预期。
认知误区修正
Go语言中map属于引用类型,函数传参时只会拷贝map的指针包装结构体(仅占几个字节),不会全量拷贝底层存储的键值数据,你之前检索到的「传map会全量拷贝」的结论是错误的,性能瓶颈另有原因。
现有代码性能瓶颈
- 偶数计算存在多余的
float64类型转换开销,直接做整数除法即可 - 记忆化覆盖范围有限:仅缓存了初始输入值的序列长度,计算过程中产生的大于初始值的中间节点没有存入memo,浪费了大量重复计算
优化方案
代码修改示例
package main // project euler 014 - longest collatz sequence import ( "fmt" "time" ) func find_collatz_len(n int, memo map[int]int) int { if v, ok := memo[n]; ok { return v } var res int if n%2 == 0 { res = 1 + find_collatz_len(n/2, memo) } else { res = 1 + find_collatz_len(3*n+1, memo) } memo[n] = res return res } func main() { start := time.Now() max_length := 0 number := 0 memo := make(map[int]int) memo[1] = 1 // 边界条件初始化 for i := 1; i < 1_000_000; i++ { current_length := find_collatz_len(i, memo) if current_length > max_length { max_length = current_length number = i } } fmt.Println(max_length, number) fmt.Println("Time:", time.Since(start).Seconds()) }
可选优化:消除传参开销
如果想要彻底避免map传参的微小开销,可以将memo声明为包级全局变量,不需要作为参数传入函数。
优化后代码运行耗时通常可以降到0.1秒以内,达到预期的性能提升效果。
内容的提问来源于stack exchange,提问作者Kolom
相关产品推荐
相关产品推荐

