繁体   English   中英

使递归函数迭代?

[英]Make recursive function iterative?

当我运行以下模块时,它将运行约960次递归:

import matplotlib
import pylab

xStart = 1
debug = 'off'
xList = []
calcList = []

def collatzCalc(xStart,calcs):
    calc = 0
    xCalc = 0
    xCalc = xStart
    while xCalc > 0:
        if debug == 'on':
            print(round(xCalc))
            print(xList)
            print(calcList)

        if xCalc == 1:
            xList.append(xStart)
            calcList.append(calc)
            xStart += 1
            if debug == 'on':
                print(calcs)
                print('---------------------------')

            calcs += 1
            collatzCalc(xStart,calcs)
        else:
            if xCalc % 2 == 0:
                xCalc = xCalc / 2
                calc += 1
            else:
                xCalc = xCalc * 3 + 1
                calc += 1

calcs = 0
collatzCalc(xStart,calcs)

它引发以下错误:

Traceback (most recent call last):
  File "C:\Users\Erin Lynch\Desktop\collatzConjecture.py", line 49, in <module>
    collatzCalc(xStart,calcs)
File "C:\Users\Erin Lynch\Desktop\collatzConjecture.py", line 32, in collatzCalc
    collatzCalc(xStart,calcs)
  File "C:\Users\Erin Lynch\Desktop\collatzConjecture.py", line 14, in collatzCalc
    while xCalc > 0:
RuntimeError: maximum recursion depth exceeded in comparison

我知道为什么会这样,因为我今天读了有关递归限制的信息,但是我想知道的是如何将递归公式转换为迭代公式。 我完全不知道该怎么做,我需要知道如何做的人的帮助。

首先,在这一部分中,第一行是不必要的,因为xCalc将立即被xStart覆盖:

    xCalc = 0
    xCalc = xStart

其次,如果仔细观察代码,就会发现如果xCalc达到1 ,它将永远循环下去:

def collatzCalc(xStart,calcs):
    ...
    xCalc = xStart
    while xCalc > 0:
        ...
        if xCalc == 1:
            ...
            collatzCalc(xStart,calcs)
        else:
            ...

由于xCalc是一个局部变量 ,其他实例collatzCalc不能修改这个变量。 该功能将永远保持循环。 由于您正在检查Collat​​z猜想,因此永远在“最外层”函数中循环是有意义的,但递归地进行操作则没有意义。

我认为这是因为您混淆了该程序的两个不同部分:

  1. 您要检查每个自然数的Collat​​z猜想。
  2. 您要计算Collat​​z序列。

让我们解决第一个问题,因为它更容易。 要检查Collat​​z猜想,您只需要一个简单的循环:

def checkCollatz(xStart=1, debug=False):
    xList = []
    calcList = []
    while True:
        calc = collatzCalc(xStart, debug=debug)
        xList.append(xStart)
        calcList.append(calc)
        if debug:
            print(xStart - 1)
            print('---------------------------')
        xStart += 1

在这里,我已将全局变量( xListcalcListxStartdebug )转换为此最外层函数的局部变量。 (您可能还希望为其选择更多的描述性名称。)请注意,我已经完全消除了calcs变量,因为它看起来与xStart相同,但总是低一。

现在,要计算Collat​​z序列,我可以重用您已经拥有的东西(去除checkCollatz中使用的checkCollatz ):

def collatzCalc(xCalc, debug=False):
    calc = 0
    while xCalc > 0:
        if debug:
            print(xCalc)
        if xCalc == 1:
            return calc
        else:
            if xCalc % 2 == 0:
                xCalc = xCalc // 2
            else:
                xCalc = xCalc * 3 + 1
            calc += 1

因为Collat​​z序列始终是整数,所以不需要使用round 另外,应该使用整数除法( // )而不是浮点除法( / ),因为/会将数字强制为浮点数。

请注意,此代码中根本没有递归。 递归已被消除,并转换为checkCollatz的循环(请注意,现在有两个 while循环,而不是一个)。 您的原始代码已经大体上是迭代的,因此将其转换为递归代码并不十分复杂。

作为附带说明,请注意,通过将函数分成两个单独的函数,现在变量变少了很多,代码更易于阅读。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM