【问题标题】:Why does this code behave like tail recursion为什么这段代码表现得像尾递归
【发布时间】:2019-10-28 10:22:54
【问题描述】:

我编写这段代码是为了从中序遍历和后序遍历创建二叉树,但我偶然发现了一个令人困惑的递归解决方案,因为该程序的行为类似于尾递归调用,而不是标准递归。

我已将代码转换为通用的代码,以便每个人都更容易理解

class Test:
    def func(self, array):      
        if not array:
            return 0
        print(array)
        array.pop(0)
        temp1 = self.func(array)
        temp2 = self.func(array)

x = [1,2,3,4,5,6]
temp = Test()
temp.func(x)    

我希望 2 个函数调用两次具有相同的输出。那就是第一次调用应该导致[2,3,4,5,6],[3,4,5,6] ... [6]。第二个函数调用应该做同样的事情。相反,第二次调用没有发生任何事情。递归堆栈不应该保存数组的当前状态,为什么要更新?

【问题讨论】:

  • 当第二个 self.func() 被调用时,第一个(及其递归子代)已经吃掉了整个数组。
  • 堆栈不包含整个数组(即列表)的副本。它包含对它的引用。只有一份清单。对它的任何机会都会反映在对它的所有引用中。

标签: python recursion tree


【解决方案1】:

array 是一个列表,一个可变对象。因此,func 正在处理对原始文件的直接引用,而不是本地副本。在func 中所做的更改是针对原来的。

【讨论】:

    【解决方案2】:

    列表是可变的。在您的递归调用中,您传递列表,在函数体中您改变列表。每个电话都在改变列表。递归堆栈不应“保持数组的当前状态”

    【讨论】:

    • 感谢您的回答。为了与 C++ 进行比较,python 中的递归调用是否仅通过引用获取对象,还是仅列出?我以为每次调用都会复制列表然后执行操作
    • 这个题目比较复杂,参考这个问题:stackoverflow.com/questions/986006/…
    • @ArslanSiddiqui 没那么复杂。 Python 中没有任何东西使用引用语义调用。每个对象都是“通过赋值”传递的,既不是通过引用调用(因为调用者看不到对参数的赋值)也不是通过值调用(因为数据不会被复制)。对象的类型根本不重要。
    【解决方案3】:

    第二次调用没有产生任何输出的原因是上面一行的递归调用。在调用 temp2 时,数组的值是 [],因为列表在此上下文中是可变的。

    temp1 = self.func(array) 将产生以下输出:

    >>> temp.func(x)
    [1, 2, 3, 4, 5, 6]
    [2, 3, 4, 5, 6]
    [3, 4, 5, 6]
    [4, 5, 6]
    [5, 6]
    [6]
    

    此函数完成后,列表已发生变异,array 的值现在为[]。您可能希望在对其执行任何突变之前创建列表的深层副本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-07
      相关资源
      最近更新 更多