GO编程语言中的斐波那契序列计算
#初学者 #编程 #go #算法

在GO中,您可以定义返回函数的函数。让我们调用第一个函数A和返回的一个B。函数b被匿名定义为以下return func() returnType {},并且可以引用函数A的变量。如果匿名函数确实来自函数A引用变量,我们说B在其引用以形成a 闭合的所有非局部变量上关闭。让我们以生成奇数的函数的示例(从书籍中获取的示例引入GO构建可靠,可扩展的程序):

func main() {
    nextOdd := MakeOddGenerator()
    fmt.Println(nextOdd()) // Prints 1
    fmt.Println(nextOdd()) // Prints 3
}

MakeOddGenerator() func() uint {
    i := uint(1)
    return func() (res uint) {
        res = i
        i = 2 * i + 1
        return
    }
}

在上面的示例中,变量i在函数nextOdd的不同调用之间保持其值。但是,它如何帮助我们计算斐波那契序列的元素?

好吧,计算斐波那契序列元素的最常用方法是使用递归,事实上,递归似乎是自然而然的。那么,让我们看一下斐波那契的序列是什么?这是一个正整数的序列(简单地说,元素列表),称为 f fib 定义为以下方式:

  • 纤维(0)= 0
  • 纤维(1)= 1
  • 对于n大于1,fib(n)= fib(n -1) + fib(n -2)

这是斐波那契序列的前15个元素:0、1 1、2、3、5、8、13、34、34、55、89、144、233、377、610。

最后一行Fib(n) = Fib(n - 1) + Fib(n - 2)是使我们对使用递归进行计算的直觉。因此,让我们实现一种递归算法来计算斐波那契序列的第n个元素:

func FibonacciRec(x uint) uint {
    if x == 0 {
        return 0
    } else if x == 1 {
        return 1
    } else {
        return FibonacciRec(x-1) + FibonacciRec(x-2)
    }
}

如果您尝试此功能,它可能与x的少量值正常工作,但是当我使用X = 50尝试时,在我的计算机上(核心i7 11th Gen,在WSL2中运行Ubuntu 16GB RAM),我得到了这些计算FIB的结果(50):

Running time of recursive Fibonacci algorithm

我不认识您,但是1分钟是“ Just” Fib(50)的长时间。当您考虑它时,这是有道理的。让我们分析fib的呼叫堆栈(n)。如果n与0或1不同,则至少需要两个其他功能来获取答案,对于每个函数,如果不是0或1,则您还需要至少两个其他功能呼叫等等。

Call stack of recursive Fibonacci sequence
(不是真正的“堆栈”,但我认为此表示可能更容易掌握)

现在,从这个“堆栈”中,您还可能会注意到某些值是计算两次的(或者如果您以更深的深度绘制堆栈),则用当前算法进行单词,我们无法重复使用在我们的情况下,已经计算出的值,例如FIB(N-2)和FIB(N-3)。

让我们尝试使用GO中的封闭来解决此问题。首先,我们需要一个返回函数的函数:

func FibonacciDyna() func(y int) int {

    return func(y int) int {
    }
}

接下来,我们需要“记住”序列的先前计算的元素,因为我们将数组(或在GO术语中切片)变量添加到Englobing函数:

func FibonacciDyna() func(y int) int {
    fib := []int{0,1}
    return func(y int) int {
    }
}

请注意,我们添加了斐波那契序列的前两个元素。然后,我们需要考虑多种情​​况,但是在此之前,我们还必须注意序列的nth元素与数组的第n个元素的对应:

func FibonacciDyna() func(y int) int {
    fib := []int{0,1}
    return func(y int) int {
        // negative numbers are not supported
        if y < 0 {
            panic("negative number not supported")
        }
        // We already computed the value.
        if y < int(len(fib)) {
            return fib[y]
        }
        // We have the two previous value Fib(n-1) and
        // Fib(n-2) needed for computation.
        if y-2 >= 0 && y < len(fib) {
            // Store the newly computed value
            fib = append(fib, fib[y-1]+fib[y-2])
            return fib[y]
        }
        // We don't have one or both of the two previous
        // value needed for computation.
        // We then compute and store all the missing values.
        for i:= len(fib); i<= y; i++ {
            fib = append(fib, fib[y-1]+fib[y-2])
        }
        return fib[y]
    }
}

您甚至可以添加一些测试:

func TestFibonacciOf0ShouldReturn0(t *testing.T) {
    x := 0
    want := 0

    getFibDyn := FibonacciDynamic()
    have := getFibDyn(x)

    if want != have {
        t.Fatalf(`FibonacciDynamic(%d) = %d, want equal for %d`, x, have, want)
    }
}

func TestFibonacciOf1ShouldReturn1(t *testing.T) {
    x := 1
    want := 1

    getFibDyn := FibonacciDynamic()
    have := getFibDyn(x)

    if want != have {
        t.Fatalf(`FibonacciDynamic(%d) = %d, want equal for %d`, x, have, want)
    }
}

func TestFibonacciOf10ShouldReturn55(t *testing.T) {
    x := 10
    want := 55

    getFibDyn := FibonacciDynamic()
    have := getFibDyn(x)

    if want != have {
        t.Fatalf(`FibonacciDynamic(%d) = %d, want equal for %d`, x, have, want)
    }
}

现在让我们运行:

Running time of dynamic Fibonacci algorithm

好多!

就是这样,让我知道您在下面的评论中的想法!

您可能会找到源代码here