简体   繁体   English

将递归转换为尾递归

[英]converting recursion to tail recursion

I was reading on converting recursive algorithms to iterative algorithms. 我正在阅读将递归算法转换为迭代算法的内容。 I came across a blog-post http://blog.moertel.com/posts/2013-05-11-recursive-to-iterative.html explaining the procedure to convert recursive algorithms first to tail recursive algorithms and then convert tail recursive to iterative one. 我遇到了一个博客文章http://blog.moertel.com/posts/2013-05-11-recursive-to-iterative.html,解释了将递归算法首先转换为尾递归算法,然后再将尾递归转换为迭代的。 In the post, it is explained that when we want to convert a recursive algorithm to a tail recursive one, we should first understand what is going on between the return of the recursive call and the return statement of the calling function. 在帖子中,解释了当我们要将递归算法转换为尾递归算法时,我们应该首先了解return of the recursive callreturn statement of the calling function.return statement of the calling function.之间发生了什么return statement of the calling function. Once that is done, we should try to add a secret feature/ accumulator parameters to the recursive function and then decide what to return. 完成此操作后,我们应尝试向递归函数添加秘密要素/累加器参数,然后确定要返回的内容。 I have followed the concept for the examples given in the blog-post but I am not able solve the exercise given at the end of the blog. 我已经按照博客文章中给出的示例的概念进行操作,但是我无法解决博客结尾处给出的练习。 I am not able to decide what should my accumulator parameter be? 我无法决定我的累加器参数应该是什么? How should I make decisions based upon that accumulator parameter. 我应该如何基于该累加器参数来做出决策。 I don't want a solution but some pointers regarding how should I think to solve this problem. 我不想要解决方案,但有一些关于如何解决该问题的建议。 Here is the exercise code: 这是练习代码:

def find_val_or_next_smallest(bst, x):
    """Get the greatest value <= x in a binary search tree.

    Returns None if no such value can be found.

"""
    if bst is None:
        return None
    elif bst.val == x:
        return x
    elif bst.val > x:
        return find_val_or_next_smallest(bst.left, x)
    else:
        right_best = find_val_or_next_smallest(bst.right, x)
        if right_best is None:
            return bst.val
        return right_best 

Thanks in advance! 提前致谢!

I post this to replace my comments from yesterday and to show the code. 我张贴此内容以替换昨天的评论并显示代码。

In a recursive algorithm each call creates a stack frame containing the functions's local variables and the passed arguments. 在递归算法中,每个调用都会创建一个堆栈框架,其中包含函数的局部变量和传递的参数。 All stack frames together hold some kind of state information. 所有堆栈帧一起保存某种状态信息。 When you are going to avoid the recursion, there will be no additional stack frames. 当您要避免递归时,将没有其他堆栈框架。 The important part of the data must be therefore maintained in the non-recursive function. 因此,必须在非递归函数中维护数据的重要部分。

Now to the code. 现在到代码。 I tried to closely follow the instructions. 我试图严格按照说明进行操作。

This is the original source. 这是原始来源。 I just omitted the docstring and replaced elif s occuring immediately after return by if s (just a matter of preferred style). 我只是省略了文档字符串,并用if s替换了return后立即出现的elif (只是首选样式的问题)。

def find_val_or_next_smallest1(bst, x):
    if bst is None:
        return None
    if bst.val == x:
        return x
    if bst.val > x:
        return find_val_or_next_smallest1(bst.left, x)
    else:
        right_best = find_val_or_next_smallest1(bst.right, x)
        if right_best is None:
            return bst.val
        return right_best

Now to the tail recursion. 现在到尾递归。 There are four branches. 有四个分支。 Two non-recursive, one already tail recursive and the fourth needs rewriting: 两种非递归,一种已经是尾递归,第四种需要重写:

    right_best = find_val_or_next_smallest1(bst.right, x)
    if right_best is None:
        return bst.val
    return right_best

This branch chooses as the result either the bst.val or the result of the call, whichever is better. 该分支选择bst.val或调用结果作为结果,以较优者为准。 The call must be done last, so the bst.val simply must be passed to it. 该调用必须最后完成,因此必须直接将bst.val传递给它。 The function gets a new parameter with the meaning "return this if you do not find anything better". 该函数将获得一个新参数,其含义是“如果找不到更好的参数,请返回此参数”。 Before the change it was "return None if you do not find a anything". 更改之前为“如果找不到任何内容,则不返回任何内容”。 So we just have to replace the None value. 因此,我们只需要替换None值即可。 I call the new parameter found , because it is what we have found so far. 我称这个新参数为found ,因为它是到目前为止我们发现的。

def find_val_or_next_smallest2(bst, x, found=None):
    if bst is None:
        return found
    if bst.val == x:
        return x
    if bst.val > x:
        return find_val_or_next_smallest2(bst.left, x, found)
    else:
        return find_val_or_next_smallest2(bst.right, x, found=bst.val)

Straightforward conversion as in the blog: 博客中的直接转换:

def find_val_or_next_smallest3(bst, x, found=None):
    while True:
        if bst is None:
            return found
        if bst.val == x:
            return x
        if bst.val > x:
            bst, x, found =  bst.left, x, found
        else:
            bst, x, found =  bst.right, x, bst.val

and cleanup: 和清理:

def find_val_or_next_smallest4(bst, x):
    found=None
    while True:
        if bst is None:
            return found
        if bst.val == x:
            return x
        if bst.val > x:
            bst = bst.left
        else:
            bst, found = bst.right, bst.val

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

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