【问题标题】:Recursive methods to create Streams in Scala在 Scala 中创建流的递归方法
【发布时间】:2012-02-01 13:59:27
【问题描述】:

这是my previous question的后续行动。

正如我understand 一样,以下计算斐波那契数的方法效率低下,因为每个斐波那契数都会调用 fib 方法,并且每次调用它都会创建一个新流。

def fib:Stream[Int] =
  Stream.cons(1, Stream.cons(1, (fib zip fib.tail) map {case (x, y) => x + y}))

另一方面,尾递归方法(如here)看起来非常有效,并计算O(1)中的每个斐波那契数

def fib(a:Int, b:Int):Stream[Int] = Stream.cons(a, fib(b, a+b));

现在我得出结论,创建 Streams 的递归方法是有效的当且仅当它们是尾递归的。对吗?

【问题讨论】:

  • 这两个例子都不是尾递归的。
  • @DanielC.Sobral 你能解释一下为什么第二个实现在O(1) 中计算每个斐波那契数,但第一个在O(N) 中计算
  • 哎呀对不起...我说的是第一个...让我删除我的评论...
  • 安迪已经回答了这个问题,但我会尝试举一个更具说明性的例子。

标签: scala stream fibonacci


【解决方案1】:

不,尾递归是为了帮助编译器循环而不是堆栈(全局),它是编译时优化。

问题来自第一个实现,其中多次调用fib 会导致多个 Stream 构造,因此一遍又一遍地进行相同的演算。

fib zip fib.tail
//if we are at the 1000, it will compute million Streams

如果你想看它,试试下面的

var i = 0
def fib:Stream[Int] = {
  i = i + 1
  println("new Stream : " + i)
  Stream.cons(1, Stream.cons(1, (fib zip fib.tail) map {case (x, y) => x + y}))
}

【讨论】:

    【解决方案2】:

    我尝试改进Andyanswer,但他几乎做到了。第一个解决方案是创建一个流金字塔——每次调用fib 都会创建另一个斐波那契流,而这些新流中的每一个都会自己创建新流,以此类推。

    需要明确的是,调用fib会产生三个流:

    • fibfib zip fib.tail 创建的
    • fib.tailfib zip fib.tail 创建的
    • map 创建的一个(请记住,map 创建一个新集合)

    由于前两个是对fib 的调用,因此它们将分别创建三个流,依此类推。

    这是它的粗略“图片”:

                              1
                              1
              1               2               1
              1               3       1       2       1
        1     2       1       5       1       3   1   2   1
        1     3   1   2   1   8   1   2   1   5   1   3 1 2 1                          
    

    这种情况一直持续下去。中间流是使用其左侧和右侧的最高流(fib 和 fib.tail)计算的。它们中的每一个都是使用它们的左右的较低流计算的。这些较低的流中的每一个都是使用最后一行显示的流计算的。

    我们可以继续这样下去,但你可以看到,当我们计算 8 时,我们已经有 14 个其他斐波那契流在进行。

    如果您将其从def 更改为val,所有这些新流都会消失,因为fibfib.tail 将引用一个现有 流而不是创建新流。由于不会创建新的流,因此不会再调用fibfib.tail

    现在,如果您查看第二个答案,您会注意到只有一个 fib 调用,并且没有 map 或类似方法,因此没有乘法效应。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-04
      • 1970-01-01
      • 2020-07-20
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多