【问题标题】:converting recursion to tail recursion将递归转换为尾递归
【发布时间】:2017-11-07 15:33:32
【问题描述】:

我正在阅读有关将递归算法转换为迭代算法的内容。我遇到了一篇博客文章http://blog.moertel.com/posts/2013-05-11-recursive-to-iterative.html,解释了首先将递归算法转换为尾递归算法,然后将尾递归转换为迭代算法的过程。在帖子中,解释了当我们要将递归算法转换为尾递归算法时,我们应该首先了解return of the recursive callreturn statement of the calling function.之间发生了什么,一旦完成,我们应该尝试添加递归函数的秘密特征/累加器参数,然后决定返回什么。我遵循了博客文章中给出的示例的概念,但我无法解决博客末尾给出的练习。我无法决定我的累加器参数应该是什么?我应该如何根据该累加器参数做出决定。我不想要一个解决方案,而是一些关于我应该如何解决这个问题的指示。下面是练习代码:

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 

提前致谢!

【问题讨论】:

  • @VPfB 谢谢。我会尽力让你知道。
  • 如果我无法通过,我会请求解决方案。
  • 是的。我正在尝试存储 nextSmallValue 并将其传递给连续的尾递归调用。但我仍然在某些情况下陷入困境。
  • 您的代码不在尾递归中,因为尾递归表明您在递归调用后没有代码。
  • 是的。我想将该代码转换为尾递归。

标签: python algorithm recursion


【解决方案1】:

我发布这个是为了替换我昨天的 cmets 并显示代码。

在递归算法中,每次调用都会创建一个堆栈帧,其中包含函数的局部变量和传递的参数。所有堆栈帧一起保存某种状态信息。当您要避免递归时,不会有额外的堆栈帧。因此数据的重要部分必须在非递归函数中维护。

现在看代码。我试图严格按照说明进行操作。

这是原始来源。我只是省略了文档字符串,并将紧跟在return 之后的elifs 替换为ifs(只是首选样式问题)。

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

现在到尾递归。有四个分支。两个非递归,一个已经尾递归,第四个需要重写:

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

此分支选择bst.val 或调用结果作为结果,以更好者为准。调用必须最后完成,所以必须将bst.val 简单地传递给它。该函数获取一个新参数,其含义是“如果您没有找到更好的东西,请返回此参数”。在更改之前,它是“如果您没有找到任何东西,则返回 None”。所以我们只需要替换 None 值。我将新参数称为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)

博客中的直接转换:

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

和清理:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-27
    • 1970-01-01
    • 2023-01-13
    • 2019-09-14
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 2011-06-30
    相关资源
    最近更新 更多