Python -While循环递归

时间:2018-03-07 18:33:38

标签: python loops recursion while-loop

如何将下面的代码转换为递归?

def fibonacci(n):
    a, b = 0, 1
    fibonacci = [0]
    while a < n:
        fibonacci.append(b)
        a, b = b, a+b
    print ('The fibonacci sequence is : '+" ".join(map(str,fibonacci)))

所以基本上我正在尝试写一个接收a的函数fibonacci number作为参数并计算斐波那契数列。 我能够提出上面的迭代方法,但它必须是递归的。 这是我到目前为止在转换为递归方面所做的事情,但它没有给我提供我需要的输出

def fibo(n, a = 0, b = 1, fib = [0]):
    if a < n:
        fib.append(b)
        a, b = b, a + b

        return fib
    return fibo(n, a, b, fib)

5 个答案:

答案 0 :(得分:2)

怎么样?:

def fibonacci(n, a=0, b=1):
   if a >= n : return [a]
   return [a] + fibonacci(n,b,a+b)

[编辑]以下是它的工作原理:

该函数通过向下一次调用自身的结果添加一个元素[a]来逐步构建数组。

第一行允许它在达到目标时停止。没有它,函数的第二行将继续调用自身,并且永远不会有来自递归的结果。

因为函数的参数对于每个调用都是本地的,所以第二次调用中a和b的值与之前的调用不同。

如果我们遵循斐波那契(7)的逻辑,我们得到:

1)斐波纳契(n = 7,a = 0,b = 1)==&gt;将返回[0] +斐波那契(7,1,1)。

2)斐波那契(n = 7,a = 1,b = 1)==&gt;将返回[1] +斐波那契(7,1,2)。

3)斐波那契(n = 7,a = 1,b = 2)==&gt;将返回[1] +斐波那契(7,2,3)。

4)斐波那契(n = 7,a = 2,b = 3)==&gt;将返回[2] +斐波那契(7,3,5)。

5)斐波纳契(n = 7,a = 3,b = 5)==&gt;将返回[3] +斐波那契(7,5,8)。

6)斐波纳契(n = 7,a = 5,b = 8)==&gt;将返回[5] +斐波那契(7,8,13)。

7)斐波那契(n = 7,a = 8,b = 13)==&gt; 8> = 7,因此第一行返回[8]

此时不再有递归调用(第一行返回而不再调用该函数)并且返回值开始重新开始。

7)返回[8]

6)返回[5,8]

5)返回[3,5,8]

4)返回[2,3,5,8]

3)返回[1,2,3,5,8]

2)返回[1,1,2,3,5,8]

1)返回[0,1,1,2,3,5,8]

考虑递归函数的一种方法是仅查看要对先前参数值生成的结果执行的增量工作。大多数情况下,这部分逻辑向后应用(即根据前一个计算最终结果)。例如,阶乘可以被认为是数字与前一数字的阶乘的乘积。

这相当于第二行。

一旦你失败了,你需要决定的是使递归停止的条件。通常这对应于最小/最简单的用例。例如,当数字小于2时,factorial不需要递归,因此函数可以直接返回1。

这相当于第一行。

正如您在上面的跟踪中所看到的,该函数将继续“前进”,但实际上最终会在完成该过程之前等待自身的结果(具有不同的参数)。这就是递归函数的工作原理。最终结果通常是在返回值从多个自调用堆栈中恢复时构建的。

您的斐波纳契函数比因子更复杂,因为该序列只能从原始(0,1)值计算。与阶乘不同,我们没有足够的信息来根据提供的参数(n)计算出a和b的值。

而且,如果你想在神秘的代码中沾沾自喜,这是一个单行版本:

def fibo(n,a=0,b=1):return [a]+fibo(n,b,a+b) if a < n else [a]

答案 1 :(得分:1)

递归实现的目的是组织这样的事情:

if we're at a base case:
    return the result for that base case
else:
    call ourselves with a reduced case
    possibly modify the result
    return the result

对于基本情况a < n,您所做的事情应与迭代版本中while循环之后的操作相关。将最后一个值添加到累加器列表fib并返回它是有意义的。它可能是也可能不对,但它至少在正确的方向上。

但是在你的递归案例中,你并没有用减少的案例来称呼自己,你只是用完全相同的论点来称呼自己。这显然是一个无限循环。 (好吧,Python不会进行尾部调用消除,所以它会成为堆栈溢出,显示为最大递归异常,但这并不好。)

那么,你应该怎么做?与原始非递归while循环内发生的事情有关的东西。你在那里做的是:

fibonacci.append(b)
a, b = b, a+b

所以,相当于:

fib.append(b)
return fibo(n, b, a+b, fib)

同样,这可能不对,但它正朝着正确的方向发展。所以,如果你明白了,你应该能够从那里继续调试全部功能。

答案 2 :(得分:0)

我认为Dash的答案是正确的,模数是几个冒号。原始问题要求计算,而不是打印。

我添加了一个dict来存储计算值以加快速度,这段代码对我有用:

fib = {}
fib[0] = 0
fib[1] = 1
def fibonacci(n):
    if n not in fib.keys():
        fib[n] = fibonacci(n - 1) + fibonacci(n - 2)
    return fib[n]

if __name__=="__main__":
    for i in range(10):
        print i, fibonacci(i)

输出:

0 0
1 1
2 1
3 2
4 3
5 5
6 8
7 13
8 21
9 34

答案 3 :(得分:0)

递归是一种功能性传承

递归是一种来自功能风格的概念。混合命令式突变(如append)和重新分配如a, b = b, a + b是新程序员痛苦和困惑的根源

def fibseq (n, a = 0, b = 1, seq = []):
  if n == 0:
    return seq + [a]
  else:
    return fibseq (n - 1, b, a + b, seq + [a])

for x in range (10):
  print (fibseq (x))

# [0]
# [0, 1]
# [0, 1, 1]
# [0, 1, 1, 2]
# [0, 1, 1, 2, 3]
# [0, 1, 1, 2, 3, 5]
# [0, 1, 1, 2, 3, 5, 8]
# [0, 1, 1, 2, 3, 5, 8, 13]
# [0, 1, 1, 2, 3, 5, 8, 13, 21]
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

答案 4 :(得分:-4)

def fibonacci(n):
    if n == 0:
        return 0
    elif n == 1
        return 1
    else
        return fibonacci(n - 1) + fibonacci(n - 2)