走路一棵树,父母先行

时间:2009-10-23 22:55:14

标签: algorithm tree hierarchy

访问链接树的所有节点的最佳方法是什么(所有节点都引用了父节点和所有子节点,根节点的空节点为null),以便在任何节点之前没有访问任何节点?布朗尼指出非递归。

10 个答案:

答案 0 :(得分:6)

伪代码:

NodesToVisit = some stack or some list
NodesToVisit.Push(RootNode)

While NodesToVisit.Length > 0
{
   CurNode = NodesToVisit.Pop()
   For each Child C in CurNode
        NodesToVisit.Push(C)
   Visit(CurNode) (i.e. do whatever needs to be done)
}

修改:递归与否?
为了在技术上正确,并且正如AndreyT和其他人在本文中指出的那样,这种方法 一种 递归算法的形式,其中使用明确管理的堆栈代替CPU堆栈和递归发生在While循环的级别。这就是说,它与递归实现本身的区别在于几种微妙而重要的方式:

  • 只有“变量”被压入堆栈;堆栈上没有“堆栈帧”和相关的返回地址,唯一的“返回地址”是while循环隐含的,只有一个实例。
  • “堆栈”可以用作列表,从而可以在列表中的任何位置使用下一个“帧”,而不会以任何方式制动逻辑。

答案 1 :(得分:5)

答案 2 :(得分:3)

您正在寻找前序遍历。我认为你可以非递归地使用它 一个队列:在伪代码中:

创建一个空队列,然后按下根节点。

while nonempty(q)
  node = pop(q)
  visit(node)
  foreach child(node)
    push(q,child)

答案 3 :(得分:3)

如果你有所有孩子和父母的链接,那么非递归算法相当简单。忘记你有一棵树。可以想象它是一个实验室,每个亲子链接都是从一个交汇点到另一个交汇点的普通双向走廊。走完整个迷宫所需要做的就是转入每个交叉路口左侧的下一个走廊。 (或者,将它想象为走在迷宫中,左手始终触及左侧的墙壁)。如果你从根交叉点开始(并向任何方向移动),你将走遍整个树,总是在孩子面前访问父母。在这种情况下,每个“走廊”将被移动两次(在一个方向和另一个方向),并且每个“交叉点”(节点)将被访问多次“走廊”加入它。

答案 4 :(得分:1)

使用一组节点。将根放在集合中以开始。然后在循环中,将一个节点拉出集合,访问它,然后将其子节点放入集合中。当集合为空时,您就完成了。

答案 5 :(得分:1)

在伪代码中:

currentList = list( root )
nextList = list()
while currentList.count > 0:
    foreach node in currentList:
        nextList.add(node.children)
    currentList = nextList

答案 6 :(得分:1)

如果从根节点开始,只访问已访问过的节点的父节点/子节点,则无法遍历树,以便在访问其祖先之前访问节点

任何类型的遍历,深度优先(基于递归/堆栈),广度优先(基于队列),深度限制,或者只是将它们从无序集中拉出来都可以。

“最佳”方法取决于树。宽度优先适用于树枝很少的高大树。对于有许多树枝的树木,深度首先适用。

由于节点实际上有指向父节点的指针,因此还有一个常量内存算法,但速度要慢得多。

答案 7 :(得分:1)

我不同意广度优先搜索,因为空间复杂性通常是特定搜索算法的祸根。可能使用迭代加深算法是这种类型的使用的更好的替代方案,并且它涵盖与广度优先搜索相同类型的遍历。在处理广度优先搜索的边缘方面存在细微的差别,但是(伪)编码不应该太难。

参考: http://en.wikipedia.org/wiki/Iterative_deepening

答案 8 :(得分:1)

这是真正的非递归方法:没有堆栈,不变空间。这个Python代码假设每个节点都包含一个子节点列表,并且节点对象没有定义相等性,因此'index'函数正在比较标识:

def walkTree(root, visit_func):
    cur  = root
    nextChildIndex = 0

    while True:
        visit_func(cur)

        while nextChildIndex >= len(cur.children) and cur is not root:
            nextChildIndex = cur.parent.children.index(cur) + 1
            cur  = cur.parent

        if nextChildIndex >= len(cur.children):
            break

        cur = cur.children[nextChildIndex]
        nextChildIndex = 0

我确信它可以被打磨一下,更简洁,更容易阅读,但这就是要点。

答案 9 :(得分:0)

在根(级别0)构建节点列表,依次遍历每个节点并查找直接子节点(其父节点是我们当前正在查看的节点)(级别1),当完成级别时0继续迭代1级,依此类推,直到你没有剩余的未访问节点。