简体   繁体   English

Python:列表如何在递归中工作

[英]Python: how does list work within recursion

I'm trying to print the path(from root to leaf node) for a binary tree. 我正在尝试打印二叉树的路径(从根到叶节点)。 I was trying to use a list as input to record the path and return it. 我试图使用列表作为输入来记录路径并返回它。

However, the return value is empty, I can see the path is being generated correctly, by printing the path at the recursion function. 但是,返回值是空的,通过在递归函数上打印路径,我可以看到路径正在正确生成。

Case 1: 情况1:

Input:
res = printPath(root, node,[]) 

Output:
res = []

My question is, how does list work with recursion, how does python handle the scope of it? 我的问题是,列表如何与递归一起使用,python如何处理它的范围?

Case 2: 情况2:

Input:
p_ = []

res = printPath(root, node, p_)

Output:
res != []

also res is not equal to the final path, which inside the recursion, can you please let me know why is that. 另外res不等于最终路径,它在递归内,请让我知道为什么。 Eg, path = [3, 5], res = [] 例如,路径= [3,5],分辨率= []

res is not empty but it will have some middle value of the recursion. res不是空的,但它将具有一些中间值的递归。 I guess, in this case, the list is treated as a pointer. 我猜在这种情况下,列表被视为指针。

If you can let me know the difference between these 2 cases, it would be great. 如果您可以让我知道这两种情况之间的区别,那就太好了。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def printPath(self, root, node, path):
        if root:
            # print root.val, node
            if root.val == node:
                path.append(node)
                print path
                return path
            if root.left:
                path.append(root.val)
                self.printPath(root.left, node, path)
            if root.right:
                path.append(root.val)
                self.printPath(root.right, node, path)

    def lowest_main(self, root, p):
        # print root.val, p
        p_ = []
        print self.printPath(root, 5, p_)
        # print p_

Because: 因为:

>>> [].append(2)
>>> []
[]
>>> l=[]
>>> l.append(2)
>>> l
[2]
>>> 

Because [] isn't stored anywhere, so won't update any variable, that's why. 因为[]不会存储在任何地方,所以不会更新任何变量,这就是原因。

[] would be kept in memory after append , but no way to access it. []将在append之后保留在内存中,但无法访问它。

Case 1: 情况1:

Here, you are passing a list object having zero elements, as argument to the "root invocation" of printPath() . 在这里,您要传递一个包含零个元素的列表对象,作为printPath()的“根调用”的printPath()

Inside this invocation, that empty list can be accessed with the parameter called path . 在此调用内,可以使用名为path的参数访问该空列表。

During the execution of the function, that empty list would become non-empty. 在执行函数期间,该空列表将变为非空。

But once you've exited this "root invocation" of the function, that parameter called path , which is referring to the (now non-empty) list, goes out of scope . 但是,一旦退出该函数的“根调用”,称为path参数(即引用(现在是非空的)列表) 就超出范围了

Now, you are left with no other variable (or name) referring to that non-empty list, so there is no way for you to actually look at the non-empty path and celebrate. 现在,您再也没有其他变量(或名称)引用该非空列表了,因此您无法实际观察非空路径并进行庆祝。

Case 2: 情况2:

Here also, you are passing an empty list object to your "root invocation" of printPath() . 同样,在这里,您正在将一个空列表对象传递给printPath() “根调用”。 But the difference is that even before you invoke printPath() , you have ensured that there is one more variable (or name) called p_ , which is pointing to the same empty list object that you are passing to the "root invocation". 但是不同之处在于,即使在调用printPath() ,您也要确保还有一个名为p_变量(或名称),它指向传递给“根调用”的同一空列表对象。 As with Case 1 , inside the invocation, the empty list object is accessed with the parameter name path . 情况1一样 ,在调用内部,使用参数名path访问空列表对象。 As with Case 1 , this empty list will become non-empty during the execution. 情况1一样 ,此空列表在执行期间将变为非空。 As with Case 1 , when the root invocation eventually completes execution and returns control, the parameter named path which was pointing to the (now non-empty) list object, will go out of scope, but you are still left with one more variable called p_ , pointing to the same (now non-empty) list object. 案例1一样 ,当根调用最终完成执行并返回控制时,指向path (现在是非空)列表对象的名为path的参数将超出范围,但仍然剩下一个名为p_ ,指向同一个(现在为非空)列表对象。

Reason why print self.printPath(root, 5, p_) prints None : print self.printPath(root, 5, p_)打印的原因None

Let's take a simple tree, in which the root node has a value of 0, and the left child has a value of 5. Assume that there are no other nodes in the tree. 让我们来看一棵简单的树,其中根节点的值为0,左子节点的值为5。假定树中没有其他节点。

What happens in your root invocation of printPath() : 在您的printPath()根调用中会发生什么:

You will first check if root.val == node . 您将首先检查if root.val == node The test will fail. 测试将失败。

You will next check if root.left . 接下来,您将检查if root.left The test will pass. 测试将通过。 You will enter that if block, append 0 to path, and make your second invocation of printPath() . 您将输入if块,将0附加到路径,然后第二次调用printPath() Now, carefully note the fact that the second invocation is made from within the first invocation. 现在,请注意第二个调用是在第一个调用内进行的。 The first invocation has not yet completed. 第一次调用尚未完成。 In fact, at that instant, the first invocation as well as the second invocation are both in a state of having partially executed. 实际上,在那一刻,第一次调用和第二次调用都处于部分执行的状态。 Correct? 正确? And the first invocation and second invocation at two different line numbers . 并且第一次调用和第二次调用使用两个不同的行号 The first invocation is at the line where printPath() is invoked for the left child, and the first invocation is just about to start executing at the first line of printPath() . 第一次调用在为左子对象调用printPath()的行,并且第一次调用即将在printPath()的第一行开始执行。 Correct? 正确?

What happens next? 接下来发生什么?

The second invocation also checks if root.val == node . 第二次调用还检查if root.val == node This time, the test succeeds, and it enters the if block, appends 5 to path , and returns path . 这次,测试成功,然后进入if块,将5附加到path ,然后返回path

But where does this returned value go? 但是,这种返回的价值在哪里呢? To the place where this second invocation happened ! 到第二次调用发生的地方! Which, if you remember, is another line in printPath() . 记住,这是printPath()另一行。 At that line, you are invoking printPath() , but not capturing its return value in any variable -- you are just ignoring its return value. 在那一行,您正在调用printPath() ,但没有在任何变量中捕获其返回值-您只是忽略了它的返回值。 So, the 0 5 string returned by the second invocation is being ignored. 因此,第二次调用返回的0 5字符串将被忽略。 The execution of the first invocation continues until it reaches the last line of printPath() . 继续执行第一次调用,直到到达printPath()的最后一行。 At the last line, there is no other return statement. 在最后一行,没有其他return语句。 So, in the absence of an explicit return statement, any Python function will return None . 因此,在没有显式return语句的情况下,任何Python函数都将返回None So, this first invocation will return None , to the place where your first invocation happened (I think that is in lowest_main() ). 因此,该第一次调用将把None返回到第一次调用发生的位置(我认为这是在lowest_main() )。

The first invocation is printing this None value. 第一次调用是打印此None值。

How to correct: 纠正方法:

To correct this, please change the following line: 要更正此问题,请更改以下行:

self.printPath(root.left, node, path)

to this: 对此:

return self.printPath(root.left, node, path)

Similarly, please change the following line: 同样,请更改以下行:

self.printPath(root.right, node, path)

to this: 对此:

return self.printPath(root.right, node, path)

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

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