当前位置: 首页 > 知识库问答 >
问题:

如何将下面的函数变成尾递归函数?

壤驷经国
2023-03-14

我一直在关注这一点,我试图获得一些将普通递归函数转换为尾部递归函数的实践。我设法理解斐波那契和阶乘的版本,但这一个难住了我。我理解算法在做什么,以及在转换中让我困惑的else语句。

在else中,它试图找到一个更接近你想要的数字,然后放弃,并继续使用它找到的数字,该数字低于你建议的数字。

我不知道如何编写使这个尾部递归的辅助函数。对于斐波那契和阶乘,我最终使用了累加器。有没有类似的东西可以在这里使用?

class BSTNode(object):
    """Binary search tree node."""

    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

    def __repr__(self):
        return '(%s, %r, %r)' % (self.val, self.left, self.right)

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

我知道Python不支持尾部递归优化以允许恒定的堆栈空间,但我只是为了在Python中练习,因为我喜欢语法

共有2个答案

吴子昂
2023-03-14

要将函数转换为尾部递归函数,您应该通过添加一个额外的参数val始终携带部分答案:

def find_val_or_next_smallest(bst, x, val=None):
    """
    Get the greatest value <= x in a binary search tree.
    Returns None if no such value can be found.
    """
    if bst is None:
        return val
    elif bst.val == x:
        val = x
    elif bst.val < x and (val is None or bst.val > val):
        val = bst.val

    if bst.val > x:
        return find_val_or_next_smallest(bst.left, x, val)
    else:
        return find_val_or_next_smallest(bst.right, x, val)

更新

拥有尾递归意味着我们可以有一个迭代解决方案(与递归相比),并且可以很容易地在接受的答案上进行演示——通过将其转换为迭代解决方案:

def find_val_or_next_smallest(bst, x, val=None):
    """
    Get the greatest value <= x in a binary search tree.
    Returns None if no such value can be found.
    """
    while True:
        if bst is None:
            return val
        elif bst.val == x:
            return x
        elif bst.val > x:
            bst = bst.left
        else:
            val = bst.val
            bst = bst.right       
邰英毅
2023-03-14

而不是做

if right_best is None:
    return bst.val

您可以将目前为止找到的最佳结果作为额外参数传递给递归调用,并让递归调用处理此检查。

def find_val_or_next_smallest(bst, x, best=None):
    """
    Get the greatest value <= x in a binary search tree.
    Returns None if no such value can be found.
    """
    if bst is None:
        return best
    elif bst.val == x:
        return x
    elif bst.val > x:
        return find_val_or_next_smallest(bst.left, x, best)
    else:
        # bst.val is guaranteed to be the best yet, since if we had
        # seen a better value higher up, the recursion would have gone
        # the other way from that node
        return find_val_or_next_smallest(bst.right, x, bst.val)
 类似资料:
  • 我有一个家庭作业问题,它给出了一个递归函数,我必须使用尾部递归来实现它。函数为f(0)=1 f(n)=1 2*f(n-1) 我并不擅长尾部递归,我试着查找示例,但我发现的都是没有斐波那契序列的示例,这没有多大帮助。 我真正拥有的是 我知道尾递归基本上每次调用都计算函数,我只是不知道如何实现它。 编辑:我打了一个错字f(n)应该是1 2*f(n-1)

  • 各种各样的书籍、文章、博客帖子表明,将递归函数重写为尾部递归函数可以加快速度。毫无疑问,对于生成斐波那契数或计算阶乘等琐碎情况,它会更快。在这种情况下,有一种典型的重写方法,即使用“辅助函数”和用于中间结果的附加参数。 尾部递归很好地描述了尾部递归函数和非尾部递归函数之间的差异,以及如何将递归函数转换为尾部递归函数。对于这种重写来说什么是重要的-函数调用的数量是相同的(重写之前/之后),不同之处在

  • 我仍在尝试实现2-3个手指树,并取得了良好的进展(存储库)。在做一些基准测试时,我发现当树非常大时,我非常基本的toList会导致堆栈溢出异常。起初,我看到了一个简单的修复方法,并将其设置为尾部递归。 不幸的是,事实证明,toList不是罪魁祸首,但viewr是: 寻找唯一的递归调用很明显,这不是尾部递归。不知何故,我希望这个问题不会存在,因为这个调用被包装在一个类似于连续的延迟中。 我听说并读过

  • 假设我编写这样的代码: 我如何让Kotlin优化这些相互递归的函数,以便在不抛出StackOverflower错误的情况下运行main?tailrec关键字适用于单函数递归,但没有更复杂的功能。我还看到一个警告,在使用关键字tailrec的地方没有找到尾部调用。也许这对编译器来说太难了?

  • 在我的Scala应用程序中,我有一个函数调用一个函数,该函数返回Future[T]类型的结果。我需要在递归函数调用中传递映射的结果。我希望这是尾递归的,但地图(或flatMap)正在破坏这样做的能力。我收到错误“递归调用不在尾部位置”。 下面是这个场景的一个简单示例。如何修改它以使调用是尾部递归的(而不破坏使用Await.result()的未来的好处)?

  • 嗯,我已经试过多次了。不过,我一度认为最长的序列函数会有所帮助,因为它显示的是最长的冰雹序列。尽管如此,我似乎不知道如何查找或存储它用于查找的值。如果有人能解释一下,我将不胜感激。 我遇到的问题是我最长的启动顺序: 我不知道如何将其转换为递归,我注意到对于一些递归,我看到人们仍然在使用for循环,但我确信我们不应该使用循环。这可能是一个愚蠢的问题,但如果有人知道的话,有没有一个公式可以将循环转换为