这涉及Python如何通过引用传递或传递值,具体取决于对象是否是不可变的。我能够递归遍历二叉树并打印出所有值,但如果我想返回一个特定的元素,那就更难了。在下面的代码中,我(两次)尝试返回一个节点,如果它的数据属性与传入的整数匹配.n1和n2是那些int值。
def get_node(self, d, root, n=[]):
if (root == None):
return
else:
if(root.data == d):
n.append(root)
self.get_node(d,root.left)
self.get_node(d, root.right)
return n
def tree_traversal(self, n1, n2):
n1 = self.get_node(n1,self.root)[0]
n2 = self.get_node(n2,self.root)[1]
print(n1.data)
print(n2.data)
return self.helper(n1,n2)
这很有效,我得到一个包含我正在寻找的节点对象的列表。但是,如果不是返回(并作为参数传递)列表,而是使用字符串或None对象以后更改,这不起作用。我认为这是因为列表是可变的而字符串不是。更重要的是,你会看到我必须将n [1]分配给n2,因为出于某种原因,即使在退出get_node递归调用并再次为n2重复执行之后,返回的列表仍然在第0个索引中包含n1。 / p>
有人可以解释为什么在分配到n2时列表仍然被修改了吗?有没有办法代替传递作为参数并返回一个空列表n,作为参数传递并返回一个默认值为None的常规对象?
答案 0 :(得分:1)
你的第一个问题是:
def get_node(self, d, root, n=[]):
有许多关于不使用可变数据来默认参数的警告。我们不是在讨论通过引用传递,也不是在这里传递值(Python 仅通过 value - 它通过值传递指向容器的指针 - 通过引用传递是某种东西完全没问题。)这里的问题是默认值只评估一次,因此 所有 后续调用将使用 相同的 < / strong>结构。这就是你:
的原因必须将n [1]分配给n2,因为出于某种原因,甚至在之后 退出get_node递归调用并再次执行此操作 n2,返回的列表仍包含第0个索引中的n1
现在你知道原因了。这与在递归期间使用全局存储结果几乎相同。避免它。
您的功能似乎没有正确设计。如果我们正在使用树,那么我们应该能够在树中的任何位置执行get_node()
或tree_traversal()
,代码中应该没有固定的root
。此外,使n1
和n2
在同一函数中具有不同的类型和含义令人困惑 - 使用不同的变量名称。让我们这样试试吧:
class Node():
def __init__(self, data, left=None, right=None):
assert (data is not None), "Error in tree/model logic!"
self.data = data
self.left = left
self.right = right
def get_node(self, d):
if self.data == d:
return self
if self.left is not None:
result = self.left.get_node(d)
if result is not None:
return result
if self.right is not None:
result = self.right.get_node(d)
if result is not None:
return result
return None
def tree_traversal(self, n1, n2):
node1 = self.get_node(n1)
node2 = self.get_node(n2)
return node1, node2
root = Node(0)
root.left = Node(1, Node(2), Node(3, Node(4)))
root.right = Node(5, Node(6), Node(7, Node(8), Node(9)))
print(root.tree_traversal(3, 9))
现在,让我们讨论一下这种模式是否适合您的模型。