简体   繁体   中英

Make recursive function iterative?

When I run the below module, it runs for about 960 recursions:

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)

It throws the following error:

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

I know why this is happening, because I read today about recursion limits, but what I'm wanting to know is how I can turn my recursion formulas into iterative ones. I am completely lost on how to do this, and I need help from someone who knows how.

First of all, in this part, the first line is unnecessary since xCalc will be immediately overwritten with xStart :

    xCalc = 0
    xCalc = xStart

Secondly, if you observe the code carefully, you see that if xCalc ever reaches 1 it will just loop forever:

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

Since xCalc is a local variable , other instances of collatzCalc cannot modify this variable. The function will just keep looping forever. While it makes sense to loop forever in the "outermost" function since you're checking the Collatz conjecture, it does not make sense to do it recursively .

I think it's because you have confused two distinct parts of this program:

  1. You want to check the Collatz conjecture for every natural number.
  2. You want to calculate the Collatz sequence.

Let's address the first one because it's easier. To check the Collatz conjecture, you just need a simple loop:

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

Here, I have turned the global variables ( xList , calcList , xStart , and debug ) into local variables of this outermost function. (You might also want to pick more descriptive names for them too.) Note that I have completely eliminated the calcs variable because it appears to be identical to xStart , except always lower by one.

Now, to calculate the Collatz sequence, I can reuse what you already have (stripping out the parts that were used in 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

The use of round is unnecessary since Collatz sequences are always integers. Additionally, one should use integer division ( // ) instead of floating-point division ( / ) because / will coerce your numbers into floating-point numbers.

Notice that there is no recursion at all in this code. The recursion has been eliminated and transformed into the loop in checkCollatz (notice that there are now two while loops instead of one). Your original code was already mostly iterative so converting it into a recursive one was not very involved.

As a side note, notice that by splitting the function into two separate functions, there are now much fewer variables and the code is a lot easier to read.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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