将递归函数转换为for循环和while循环

时间:2017-10-03 20:01:52

标签: python python-3.x

我需要转换

def aRecursive(n):
    if n is 1:
        return 3
    else:
        return 2 * aRecursive(n-1) + 5

进入for循环和while循环。我似乎无法围绕这个过程。这些循环的原始函数是:

a(1) = 3
a(n) = 2 * a(n-1) + 5

答案和解释会有很大帮助。

2 个答案:

答案 0 :(得分:1)

我将根据函数的调用方式提供解决方案。此解决方案是通用的,因为您可以使用相同的方法将任何递归函数转换为迭代函数。这在理论上是可行的,但似乎没有人谈论如何。由于您的功能很简单,因此不难想出迭代功能。但是如何对二叉树的非递归后序遍历呢?如果您没有我将要提供的通用方法,您只能根据具体情况进行。

我们走了。首先,我们需要稍微更改您的递归版本以便于转换:

def f(N):
    n = N        # N is the top level parameter passed to this function
    res = None   # res is the result returned by this function
[start]:         # here we create a label; not python, only for converting
    if n == 1:
        return 3
    else:
        return 2 * f(n-1) + 5

接下来我们将转换两件事:函数调用和return语句。函数调用基本上是两步:将参数和返回地址推送到堆栈并跳转到实际代码。 return基本上是弹出参数并跳转到保存的地址。所以我们走了:

def f(N):
    n = N        # N is the top level parameter passed to this function
    res = None   # res is the result returned by this function
[start]:         # here we create a label; not python, only for converting
    if n == 1:
        return 3
    else:
        push(n)       # push current parameter; since there is only one recursive function call in the body, we know where to return and there is no need to push the return address
        n = n-1       # the next level actual parameter is now n-1
        goto [start]  # we go to the code of the function which is the start of this same function
        return 2 * f(n-1) + 5  # we will never reach here... this line is where we need to return when any `return` statements is met

接下来,我们将更改第一个return语句(return 3):

def f(N):
    n = N        # N is the top level parameter passed to this function
    res = None   # res is the result returned by this function
[start]:         # here we create a label; not python, only for converting
    if n == 1:
        res = 3
        # for `return` we need to see if this is the top level or a inner recursive call
        if stack is empty: # we are in top level
            return res
        # hey we are in a recursive call, and we need to return to the code after `goto`, why not move these code here?
        else:
            n = pop()      # we pop the parameter saved
            # this line is where we need to return when any `return` statements is met
            return 2 * f(n-1) + 5
    else:
        push(n)       # push current parameter; since there is only one recursive function call in the body, we know where to return and there is no need to push the return address
        n = n-1       # the next level actual parameter is now n-1
        goto [start]  # we go to the code of the function which is the start of this same function

然后我们将转换return 2*f(n-1)+5

def f(N):
    n = N        # N is the top level parameter passed to this function
    res = None   # res is the result returned by this function
[start]:         # here we create a label; not python, only for converting
    if n == 1:
        res = 3
        if stack is empty:
            return res
        else:
            [loop]:
            n = pop()      # we pop the parameter saved
            # begin conversion of return
            res = 2*res+5
            if stack is empty:
                return res;
            else:
                # we need to pop stack and jump to the same return, so we just jump to [loop]
                goto [loop]
    else:
        push(n)       # push current parameter; since there is only one recursive function call in the body, we know where to return and there is no need to push the return address
        n = n-1       # the next level actual parameter is now n-1
        goto [start]  # we go to the code of the function which is the start of this same function

现在转换完成了,我们需要简化这个混乱。首先,我们应该考虑是否真的需要堆栈。对于这个特殊问题,每次推送只需n=n-1,每个pop都会生成n=n+1。所以堆栈并不是真的需要。

def f(N):
    n = N        # N is the top level parameter passed to this function
    res = None   # res is the result returned by this function
[start]:         # here we create a label; not python, only for converting
    if n == 1:
        res = 3
        if n == N:         # SAME as stack is empty
            return res     # really return
        else:
            [loop]:
            n = n+1       # WE JUST INCREASE N INSTEAD OF POP
            res = 2*res+5
            if n==N:      # SAME as stack is empty
                return res;
            else:
                goto [loop]
    else:
        # NO PUSH NEEDED
        n = n-1       # the next level actual parameter is now n-1
        goto [start]

删除了堆栈,我们需要使这些goto语句消失。请注意[start]标签和goto [start]制作循环,我们只需要将它们设为'while'循环:

def f(N):
    n = N        # N is the top level parameter passed to this function
    res = None   # res is the result returned by this function
    # we reverse the if n==1 and make it a condition in while
    while n != 1:
        # NO PUSH NEEDED
        n = n-1       # the next level actual parameter is now n-1
    # you soon noticed the above calculation is not needed at all, it just sets n = 1

    res = 3
    if n == N:
        return res
    else:
        [loop]:
        n = n+1
        res = 2*res+5
        if n==N:
            return res;
        else:
            goto [loop]

我们优化了第一个循环并将其替换为n=1。我们需要使[loop]goto [loop]标记的第二个循环消失:

def f(N):
    n = N        # N is the top level parameter passed to this function
    res = None   # res is the result returned by this function
    n = 1        # the result of the first while loop

    res = 3
    if n == N:
        return res
    else:
        do:              # Python does not have do while, but it is straight forward to do this convert
            n = n+1
            res = 2*res+5
        while n!=N
        return res

我们很快就会注意到前4个语句可以合并,我们会删除所有评论:

def f(N):
    n = 1
    res = 3
    if n == N:
        return res
    else:
        do:
            n = n+1
            res = 2*res+5
        while n!=N
        return res

我们将撤销if n==N声明:

def f(N):
    n = 1
    res = 3
    if n != N:
        do:
            n = n+1
            res = 2*res+5
        while n!=N
        return res
    else:
        return res

很明显return res可以置于顶层,if n!=Ndo/while循环可以合并为一个while循环:

def f(N):
    n = 1
    res = 3
    while n != N:
        n = n+1
        res = 2*res+5
    return res

这是原始递归函数的等效版本。请注意,我没有深入研究这个特定的问题来提出这个版本,我只处理函数调用转换。我建议你在自己喜欢的文本编辑器中自己完成整个过程,这很有趣。你会发现它是非常机械的,唯一需要考虑的是堆栈的使用。其他技术,如“反向条件”或“转换为结构循环”非常容易。

有趣的是,迭代版本比仅基于转换过程的递归版本更有效,因为:1。我们消除了堆栈的使用; 2.我们消除了一个将n减少到1的循环。我们至少节省了一些CPU周期和堆栈存储。

答案 1 :(得分:0)

一个可能的for循环:

def a(n):
    answer = 3

    for i in range(n - 1):
        answer = answer * 2 + 5

    return answer

可能的while循环,但我并不特别喜欢在这里使用while

def a(n):
    answer = 3

    while n > 1:
        answer = answer * 2 + 5
        n -= 1

    return answer

请注意,这些答案(或原始代码)都不会处理小于1的n

解释

a(1) = 3
a(n) = 2 * a(n - 1) + 5

因此,如果您要计算a(5),则有两种合理的方法。一个是写出一些递归的东西:

a(5) = 2 * a(4) + 5

然后计算a(4)

a(4) = 2 * a(3) + 5

所以a(5)现在是:

a(5) = 2 * (2 * a(3) + 5) + 5

您可以继续此过程,直到您不再引用a为止,然后您就可以进行算术运算。

非递归方式是计算:

a(1) = 3
a(2) = 2 * a(1) + 5  =  2 *  3 + 5  =  11
a(3) = 2 * a(2) + 5  =  2 * 11 + 5  =  27
a(4) = 2 * a(3) + 5  =  2 * 27 + 5  =  59
a(5) = 2 * a(4) + 5  =  2 * 59 + 5  =  123

这样,你从3开始,然后在每一步,乘以2并加5以获得下一个数字。当你到达试图计算函数的n时,就停止。

第二种(非递归)方法是forwhile循环上面的工作方式。