簡體   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