[英]Finding the minimum value in a binary tree, Python
我正在尝试编写一个返回二叉树而不是二叉搜索树中最小值的函数。 这是我写的,这是不正确的。
def min(root, min_t): # min_t is the initially the value of root
if not root:
return min_t
if root.key < min_t:
min_t = root.key
min(root.left, min_t)
min(root.right, min_t)
return min_t
我觉得我不太了解递归。 我似乎无法弄清楚何时在递归调用中使用return语句,何时不使用。
感谢您的见解!
这是我想出的另一种方法,它可以工作,但是效率似乎最高:
n = []
def min_tree(root, n):
if root:
n += [(root.key)]
min_tree(root.left, n)
min_tree(root.right, n)
return min(n)
思考?
迈克尔的回答解释了您应该如何解决问题,但是他没有解释您当前的尝试出了什么问题。 据我了解,您的策略是检查每个节点,并在使用过程中跟踪最低值,使用递归查找所有节点。 检查完所有节点后,您知道结果是整个树的最小值。 这是一种完全有效的方法,它会起作用,除了参数不能完全按照您期望的方式起作用。
Python通过值而不是通过引用传递参数。 当使用“ min_t = root.key”将值分配给min_t时,它仅在函数内部生效。 该函数的调用者看不到新值。
您可以使用一些简单的代码进行测试:
def add_one_to(x):
x = x + 1
print "add_one_to", x
x = 2
add_one_to(x)
print x
您可以看到在运行代码时x在函数内部但未在顶层递增的情况。
这在函数调用自身时也适用。 每个调用都有自己的一组局部变量,并且在函数内部分配给局部变量不会影响调用它的实例。
请注意,某些语言确实允许您通过引用传递参数。 如果通过引用传递参数,则在函数内部分配该参数也会影响调用方。 如果Python是这些语言之一,则可以将min_t用作引用参数,然后您的函数将正常运行。
尽管Python不直接支持引用参数,但您也可以将引用参数视为在调用时进入函数并在函数完成时传递回调用方的值。 您可以分别做这两个事情。 要将值传递回调用者,请返回该值。 然后,调用者可以将该函数分配给它的本地函数,并且您基本上已经通过引用传递了一个参数。
这是将其应用于上述示例的方法:
def add_one_to(x):
x = x + 1
print "add_one_to", x
return x
x = 2
x = add_one_to(x)
print x
只需添加一个返回值和赋值,它便可以正常工作。
您也可以将其应用于原始功能:
def min(root, min_t): # min_t is the initially the value of root
if not root:
return min_t
if root.key < min_t:
min_t = root.key
min_t = min(root.left, min_t)
min_t = min(root.right, min_t)
return min_t
我所做的就是在每次调用min()之前添加“ min_t =”,并将您的return语句更改为最后返回min_t。 (我想您可能无论如何都要返回min_t。min是函数的名称,这样就没有多大意义了。)我相信该版本会起作用。
编辑:尽管所有这些,您的min_tree函数起作用的原因是n是一个列表,并且列表是可变对象。 当我在上面谈论“价值”时,我真正的意思是“对象”。 python中的每个变量名称都映射到一个特定的对象。 如果您有这样的代码:
def replace_list(x):
x = [1, 2, 3]
x = [2]
replace_list(x)
print x
其结果是[2]。 因此,如果您使用“ x =”将新值分配给x,则调用者将看不到它。 但是,如果您这样做:
def replace_list(x):
x.append(1)
x = [2]
replace_list(x)
print x
结果是[2,1]。 这是因为您尚未更改x的值。 x仍指向同一列表。 但是,该列表现在包含一个附加值。 不幸的是,“ + =”运算符在这方面令人困惑。 您可能会认为“ x + = y”与“ x = x + y”相同,但是在Python中并非总是如此。 如果“ x”是一种特别支持“ + =”的对象,则该操作将修改该对象。 否则,它将与“ x = x + 1”相同。 列表知道如何处理“ + =”,因此将+ =与列表一起使用将在适当的位置进行修改,但对数字进行使用则不会。
您实际上可以在不执行任何函数调用的情况下进行测试:
x = [1, 2]
y = x
y += [3]
print x # [1, 2, 3]
print y # [1, 2, 3]
print x is y # True, x and y are the same object, which was modified in place
x = [1, 2]
y = x
y = y + [3]
print x # [1, 2]
print y # [1, 2, 3]
print x is y # False, y is a new object equal to x + [3]
x = 1
y = x
y += 2
print x # 1
print y # 3
print x is y # False, y is a new object equal to x + 2
对于此特定问题,您想遍历整棵树并返回所看到的最小值。 但总的来说,递归的基本原理是,然后再次调用该函数,就会看到相同问题的修改版本。
考虑一下你的树:
root
/ \
left right
当您在左侧子树上调用递归函数时,您将再次看到一棵树。 因此,您应该能够使用相同的逻辑。
递归函数的关键是基本情况和递归步骤。 在您的树示例中,基本情况不是当您找到最小值(您怎么知道?)时,而是当您到达树的底部(也就是一片叶子)时。
并且,您的递归步骤正在研究每个子问题(bin_min(左)和bin_min(右))。
最后一部分正在考虑返回值。 不变的是,您的函数已返回它所看到的最小元素。 因此,当递归调用返回时,您知道它是最小的元素,然后您需要返回的东西是三个可能选择(root,left_min和right_min)中的最小元素。
def min_bin(root):
if not root:
return MAX_VAL
left_min = min_bin(root.left)
right_min = min_bin(root.right)
return min(left_min, right_min, root.val)
请注意,这与@Rik Poggi的解决方案不同。 他使用尾部递归对其进行了一些优化。
因为您可以尝试解决这个问题,而不是使用固定的解决方案,所以这里有一些提示。 首先,您不应该将其命名为min
,因为这样做当然不能调用python的min
来测试结果。 随着迈克尔的回答让我想起了,你不必在通过min_t
,因为你可以测试root.key
代替-但我认为这是有帮助的传递min_t
来理解问题。
除此之外,您的第一行是正确的; 做得好。 :
def tree_min(root, min_t): # min_t is the initially the value of root
if not root:
return min_t
if root.key < min_t:
min_t = root.key
现在,您必须考虑返回什么。 基本上,有三个可能的最小值。 第一个是min_t
。 第二个是right
子树的最小值。 第三个是left
子树的最小值。 获取后两个值(这是递归调用所在的位置),然后返回最小值。
这是找到最小元素的递归方法:
minelement = float("inf")
def minimum(self, root):
global minelement
if root:
if root.data < minelement:
minelement = root.data
self.minimum(root.left)
self.minimum(root.right)
return minelement
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.