python 二叉树 搜寻指定节点,在二叉树(Python)中查找指定节点的路径

这篇博客讨论了在Python中计算二叉树从根节点到指定节点路径的问题。作者遇到的问题是返回的路径不正确,缺少目标值并且包含了不需要的节点。解决方案在于改进前序遍历算法,只在找到目标节点时添加值,并使用反向列表来保持正确的顺序。此外,还提到了默认参数的潜在问题,建议使用空列表作为参数以避免多次调用间的干扰。
摘要由CSDN通过智能技术生成

I'm having trouble computing the path from the root to a specified node in a binary tree (this is specifically about a Python solution to this problem).

Here's an example. Given the binary tree below, if I specify the node whose value is 4, I want to return [1, 2, 4]. If I specify the node whose value is 5, I want to return [1, 2, 5].

1

/ \

2 3

/ \

4 5

Here's my attemped solution.

class TreeNode:

def __init__(self, x):

self.val = x

self.left = None

self.right = None

def path(root, k, l=[]):

if not root:

return []

if root.val == k:

return l

# Pre-order traversal: Visit root, then left, then right.

l.append(root.val)

path(root.left, k, l)

path(root.right, k, l)

return l

Now if I run this

>>> a = TreeNode(1)

>>> b = TreeNode(2)

>>> c = TreeNode(3)

>>> d = TreeNode(4)

>>> e = TreeNode(5)

>>> a.left = b

>>> a.right = c

>>> b.left = d

>>> b.right = e

>>> path(a, 4) # should be [1, 2, 4]

[1, 2, 5, 3]

You can see that I don't get the expected. I'm sure it has to do with my traversal algorithm, but I can't figure out where I'm going wrong. Any help is greatly appreciated.

解决方案

The missing 4 is caused by the fact that you never append it. In your success case:

if root.val == k:

return l

… you need to d this:

if root.val == k:

l.append(root.val)

return l

The extra 3 and 5 are caused by the fact that you always append the value in the intermediate case, even for the nodes where you're going to backtrack.

You can fix that by only appending it if either of the recursive calls returns a non-empty list, but then of course you'll have the nodes out of order. The easiest fix for that is to intentionally get the nodes out of order:

# Pre-order traversal: Visit root, then left, then right.

if path(root.left, k, l) or path(root.right, k, l):

l.append(root.val)

… and then reverse the list at the end, e.g., in a wrapper function:

def path2(root, k):

return list(reversed(path(root, k)))

However, there's still one problem left in your code, right here:

def path(root, k, l=[]):

That [] that's the default value for l gets created one time, when the def is executed, and then reused on every call. That means that path2(a, 4) will return the right answer the first time, [1, 2, 4], but when you call it a second time, it'll keep appending to that same list and return [1, 2, 4, 1, 2, 4].

There are a couple idiomatic ways around this, but in our case, since we're already using that path2 wrapper function, we might as well just fix it there:

def path2(root, k):

return list(reversed(path(root, k, [])))

… and then get rid of the default value on path.

However, you might want to consider starting over with an easier-to-understand version:

def path(root, k):

if not root:

return []

if root.val == k:

return [root.val]

res = path(root.left, k)

if res:

return [root.val] + res

res = path(root.right, k)

if res:

return [root.val] + res

return []

(You can make this is a bit shorter; I went out of my way to make everything explicit here.)

For many recursive problems, inverting them and passing up an accumulator is an important optimization, because tail-call elimination can remove one of the branches from the stack. Even though Python doesn't do TCE, it's still worth learning how to do things the tail-calling way, just for your own understanding (and in case you ever write code in another language, of course). But learn how to do the simpler version first, and only then try to invert it.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值