我们以经典的递归求斐波那契数列为例,众所周知,递归是比较消耗内存的,且效率比较低,我们通过普通方法和加入内存缓存的方法作对比。
先来看看普通方法。
普通实现方法
package main
import (
"fmt"
"time"
)
func fibonacci(a int)(result int){
//递归需要一个出口
if a==1||a==2 {
result =1
return
}
//开始递归,前一个数加后一个数,一直调用,直到出口为止
result=fibonacci(a-1)+fibonacci(a-2)
return
}
func main(){
var i int=45
//开始调用
start:=time.Now()
num:=fibonacci(i)
fmt.Printf("第%d个斐波那契数列为%d",i,num)
end:=time.Now()
dur:=end.Sub(start)
fmt.Println("运行时间为:",dur)
}
经我这台渣渣笔记本测试,此方法求第45位所需时间为7.1s
2018.11月更新
添加内存缓存实现
上面的代码已经过时了,最近又学了一招,通过加内存缓存的方法实现快速递归求斐波那契数列。
这种方法避免了重复计算,经测试,可以将上面的代码速度提升四千倍左右。不多说,直接上代码。
package main
import (
"fmt"
"time"
)
const LIM = 45
var fibs [LIM]uint64
func fibonacci(n int) (res uint64) {
// 缓存: 检查是否已经计算过,如已有值则直接提取。
if fibs[n] != 0 {
res = fibs[n]
return
}
if n <= 1 {
res = 1
} else {
res = fibonacci(n-1) + fibonacci(n-2)
}
//计算完毕,加入缓存中,以备下次之需
fibs[n] = res
return
}
func main() {
var result uint64 = 0
start := time.Now()
for i := 0; i < LIM; i++ {
result = fibonacci(i)
fmt.Printf("fibonacci(%d) is: %d\n", i, result)
}
end := time.Now()
delta := end.Sub(start)
fmt.Printf("longCalculation took this amount of time: %s\n", delta)
}
经我这台渣渣电脑测试,求第45位数列的值所用时间约等于0.
可见速率提升了不是一点点。
总结
内存缓存的技术在使用计算成本相对昂贵的函数时非常有用(不仅限于例子中的递归),譬如大量进行相同参数的运算。这种技术还可以应用于纯函数中,
即相同输入必定获得相同输出的函数。