Python 使用DFS的树的深度

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 =

我试图用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 = 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