Go语言实现递归和分治

 

  • 个人主页:我的主页
  • 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物.

引言

        本文通过两个案例来剖析递归与分治的求解思路。案例采用Go语言来实现,通过算法也能熟悉Go编程。


算法思想

        分治的思想,也就是把规模较大的问题,拆分成规模较小,且解是相同的,以此不断拆分,直到容易得出解为止,再把各子问题合并成最终解。那这里的关键问题就是,如何拆成成同类型的子问题,很容易用到递归的方法。

        递归方法能让这类问题处理起来简单,利用递归可以迭代的将问题不断拆分,每次只考虑子问题的处理;但同样带来计算机的性能问题,计算机通过递归栈来达到递进与回归,在递归深度不大时,与非递归差别较小,当递归深度大时,反而非递归算法性能更优。


阶乘

n的阶乘表示 n!=1*...(n-1)*n ; 其中 0!= 1 ,这是要特别注意的。

对于这个问题,我们可以进行拆分子问题,先求出(n-1)!,然后再与n相乘,就可以得到n!。

那么我们先用递归方来编码实现一下:

package main

import "fmt"

func factorial(n int)(res int) {
        if n <= 1 {
                return 1
        }

        return n*factorial(n-1)
}


func main() {
        n := 5
        f := factorial(n)

        fmt.Println("n=",n,";factorial=",f)
}

用递归和分治思想的话,实现就相对简单,每次递归只关注当前子问题的解就可以。

能不能用非递归来实现呢?当然是可以的,下面用非递归方法编码:

func factorial(n int)(res int) {
        if(n < 0) {
                return 0
        }

        if(n == 0) {
                return 1
        }

        f := 1
        for i := 1; i <= n; i++ {
                f *= i;
        }
        return f
}

非递归时,我们用了循环来累积,用上面的测试程序可以验证一下,结果是一样的。


斐波那契数

        斐波那契数(Fibonacci sequence)也是一个经典的递归案例,又称黄金分割数列。

        因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……

        其中 F(0) = 1, F(1) = 1,其后F(n) = F(n-1) + F(n-2)。

从公式表达来看,可以转换为先求子问题 n-1, n-2的解,再得出n的解,那我们用递归来实现一下。

package main

import (
        "fmt"
)

func fabocci(n int) (res int) {
        if n < 0 {
                return 0
        }else if n == 0 {
                return 1
        }else if n == 1 {
                return 1
        }

        return fabocci(n-1)+fabocci(n-2)
}



func main() {
        n := 9
        f := fabocci(n)

        fmt.Println("n=", n, "; fabocci=", f)
}

​用递归和分治思想的话,实现就相对简单,每次递归只关注当前子问题的解就可以,这里是需要两个子问题的解才能得到更大子问题的解。

能不能用非递归来实现呢?当然是可以的,下面用非递归方法编码:

func fabocci(n int) (res int) {
        if n < 0 {
                return 0
        }else if n == 0 {
                return 1
        }else if n == 1 {
                return 1
        }

        f, fn1, fn2 := 0, 1, 1 // fn1-> f(n-1),fn2 -> f(n-2)
        for i := 2; i <= n; i++ {
                f = fn1 + fn2
                fn1 = fn2
                fn2 = f
        }

        return f
}

非递归时,我们依然使用了循环,但是这里用了两个fn1,fn2来记录上两次的计算结果,不断交替赋值,达到更新上两次的最新结果。

用上面的测试程序可以验证一下,结果是一样的。


结尾

作者邮箱:[email protected]
如有错误或者疏漏欢迎指出,互相学习。

注:未经同意,不得转载!

猜你喜欢

转载自blog.csdn.net/senllang/article/details/129578264
今日推荐