Python 使用DFS的树的深度
我试图用Python编写代码,使用DFS而不是BFS返回每个节点上具有任意数量子节点的树中最深叶子的深度。看起来我很接近了,但是下面的代码仍然有一些我无法理解的错误(即返回的深度不正确)。有什么帮助吗 一个测试树应该是简单的:[[1,2,3],[4,5],[6],[7],[8],[],[],[],[],[]]Python 使用DFS的树的深度,python,tree,Python,Tree,我试图用Python编写代码,使用DFS而不是BFS返回每个节点上具有任意数量子节点的树中最深叶子的深度。看起来我很接近了,但是下面的代码仍然有一些我无法理解的错误(即返回的深度不正确)。有什么帮助吗 一个测试树应该是简单的:[[1,2,3],[4,5],[6],[7],[8],[],[],[],[],[]] def max_depth_dfs(tree): # DOESN'T WORK max_depth, curr_depth, Q = 0,0, [0] visited =
def max_depth_dfs(tree): # DOESN'T WORK
max_depth, curr_depth, Q = 0,0, [0]
visited = set()
while Q != []:
n = Q[0]
more = [v for v in tree[n] if v not in visited]
if not more:
visited.add(n)
curr_depth -= 1
Q = Q[1:]
else:
curr_depth += 1
max_depth = max(max_depth, curr_depth)
Q = more + Q
return max_depth
我用了
试试。。捕捉
以区分树枝和树叶更新不再有例外:)
以下是非重现版本:
from collections import Iterable
def max_depth_no_recur(tree):
max_depth, node = 0, iter(tree)
stack = [node]
while stack:
try:
n = node.next()
except StopIteration:
if len(stack) > max_depth:
max_depth = len(stack)
node = stack.pop()
continue
if isinstance(n, Iterable):
stack.append(node)
node = iter(n)
return max_depth
我找到了虫子
if not more:
visited.add(n)
curr_depth -= 1
Q = Q[1:]
当您访问节点4时,curr_depth等于2。节点4没有子节点,因此减小curr_深度,现在curr_深度等于1。但是,您将访问的下一个节点是节点5,节点5的深度是2而不是1。因此,curr_depth不会记录树中节点的正确深度
以下解决方案可能会有所帮助
def max_depth_dfs(tree):
max_depth, curr_depth, Q = 0, 0, [0]
visited = set()
while Q != []:
n = Q[0]
max_depth = max(max_depth, curr_depth)
if n in visited:
curr_depth -= 1
Q = Q[1:]
continue
#print n, curr_depth #show the node and its depth in the tree
visited.add(n)
more = [v for v in tree[n]]
if not more:
Q = Q[1:]
else:
curr_depth += 1
Q = more + Q
return max_depth
在考虑了Alex和Adonis提供的所有良好反馈并完善了代码后,我现在有了当前版本:
def max_depth_dfs(tree): # correct
max_depth, curr_depth, Q = 0, 0, [0]
visited = set()
while Q != []:
n = Q[0]
if n in visited:
Q = Q[1:]
curr_depth -= 1
visited.remove(n) # won't go back, save memory
print 'backtrack from', n
continue
# proper place to print depth in sync with node id
print 'visiting', n, 'children=', tree[n], 'curr_depth=', curr_depth, 'Q=', Q,
print visited # only current path, instead of visited part of tree
if tree[n]:
visited.add(n) # if leaf, won't ever try to revisit
Q = tree[n] + Q
curr_depth += 1
max_depth = max(max_depth, curr_depth) # no need to check if depth decreases
else:
Q = Q[1:] # leaf: won't revisit, will go to peer, if any, so don't change depth
print 'no children for', n
return max_depth
只是为了确保问题存在于代码和需求的解释中:您希望您的示例树[[1,2,3]、[4,5]、[6]、[7]、[8]、[]、[]、[]、[]、[]中的深度是多少?代码返回了什么?是的,很好。我希望节点0的深度为0,而特定树的深度为3。[[1],[]的深度应该是1,[[1],[2],[]的深度应该是2,依此类推。对于该输入,这确实返回3您是对的,但这是一个幸运的情况。[1,2,3],[4,5],[6],[7],[],[],[8],[],[]给出了2,它应该是3。我在第一个例子中跟踪“curr_depth”,虽然它给出了3,但curr_depth是不正常的。我对树结构有点困惑。整数是一个具有数据值的叶节点,数组是一个分支节点吗?没有一个示例显示像[[1][2[3,4]]这样的进一步嵌套。这是允许的吗?由于堆栈限制,我特别不想要这个递归版本。我想使用我自己的堆栈(Q)。我的递归版本为:def max_depth(tree):def_depth(node):如果tree[node]=[]返回0,否则返回1+max(对于tree[node]中的v,返回深度(0)我还建议不要使用
except
子句,因为如果设置为catch,则几乎不可能以任何方式中断函数的执行。这很好,但需要大量的机器。我希望有更简单的东西:-)(即没有Iterable,也没有iInstance?)以前的版本不起作用。这个有Iterable
只是为了确定节点是否可以用铲斗挖掘。是的,这就是为什么我将节点id保留在堆栈上,直到其所有子节点都被探测完毕:我只在该节点不再有任何可探测内容时才执行Q=Q[1:]。此版本非常节省内存。它只在本地堆栈上保存惰性迭代器,并执行深度优先遍历。是的,迭代器非常有效。我意识到,保持“已访问”的数据结构意味着我们正在将树“复制”到该数据结构。也就是说,在执行结束时,所有节点在“树”中存储一次,在“访问”中存储一次。。。是否可以做得更好?您可以只记录所访问节点的索引,而不是将节点复制到“已访问”的数据结构中。是的,不复制整个节点本身。我考虑的更多的是根本不使用“已访问”的数据结构,无论是对整个节点,还是对节点的引用。递归版本可以做到这一点,但我认为这不是一个好主意。我想知道我们是否不能利用DFS通过树前进的方式直接“知道”哪些节点已被访问。另外,当您位于树的“右侧”时,您不需要记住在“左侧”访问了哪些节点(因为DFS永远不会回到那里)。事实上,例如,每次回到根目录时,都可以清除“已访问”(并减少内存使用)。这是真的吗?
def max_depth_dfs(tree): # correct
max_depth, curr_depth, Q = 0, 0, [0]
visited = set()
while Q != []:
n = Q[0]
if n in visited:
Q = Q[1:]
curr_depth -= 1
visited.remove(n) # won't go back, save memory
print 'backtrack from', n
continue
# proper place to print depth in sync with node id
print 'visiting', n, 'children=', tree[n], 'curr_depth=', curr_depth, 'Q=', Q,
print visited # only current path, instead of visited part of tree
if tree[n]:
visited.add(n) # if leaf, won't ever try to revisit
Q = tree[n] + Q
curr_depth += 1
max_depth = max(max_depth, curr_depth) # no need to check if depth decreases
else:
Q = Q[1:] # leaf: won't revisit, will go to peer, if any, so don't change depth
print 'no children for', n
return max_depth