Python 树模型的迭代打印

Python 树模型的迭代打印,python,tree,iteration,Python,Tree,Iteration,我有这样一个节点树: class Node: next # the next node or None prev # the previous node or None parent # the parent or None children[] # ordered list of child nodes columns[] # a list of data. Currently only holdt the

我有这样一个节点树:

class Node:
    next        # the next node or None
    prev        # the previous node or None
    parent      # the parent or None
    children[]  # ordered list of child nodes
    columns[]   # a list of data. Currently only holdt the 
                # string representation of the node in the model.
因为我不能预先知道模型有多大,所以我得出结论,递归不是一种选择。我希望在内存中保留尽可能少的节点。这是我的方法应该打印的内容:

- 0
-- 0:0
--- 0:0:0
--- 0:0:1
---- 0:0:1:0
---- 0:0:1:1
--- 0:0:2
-- 0:1
- 1
但这就是它所打印的内容:

以下是我编写的代码:

def print_tree(from_path):
    nodelist = []
    root_node = model.get_iter(from_path)
    nodelist.append((root_node, 0)) # the second item in the tuple is the indentation

    while nodelist:
        node = nodelist[0][0]
        indent = nodelist[0][1]
        del(nodelist[0])
        print("{0} {1}".format("-" * indent, node.columns[0])) 

        if node.children:
            child = node.children[0]
            nodelist.append((child, indent +1))

            while child.next:
                nodelist.append((child.next, indent +1))
                child = child.next
        if node.next:
            next = node.next
            nodelist.append((next, indent))

非常感谢您的帮助。

由于每个节点都有一个对其父节点的引用,我认为您可以遍历整个树,一次只在内存中保留一个节点。我在理解您的代码(特别是如何将每个节点加载到内存中)时遇到了一些困难,因此我将在伪代码中发布我的建议:

def visit(node,indent):
    # Load your node data
    print("{0} {1}".format("-" * indent, node.columns[0])) # Do something with your data
    # Unload your node data
    if len(node.children) > 0 :
        return (node.children[0], indent+1) # Visit the first child, if there is one
    while node.next is None: # If no sibling, your parent is done
        node = node.parent
        indent -= 1
        if node is None: # Root node reached, end the traversal
            return None
    return (node.next, indent) # Visit your next sibling, if there is one

cursor = (root_node, 0)
while cursor is not None:
    cursor = visit(*cursor)

如果节点本身必须动态加载(即
下一个
上一个
父节点
子节点
只包含到另一个节点数据的路径,而不包含对
节点
对象的引用),请告诉我,我将更新答案(只需要稍微更改一下加载/卸载的位置)。当然,如果卸载仅仅是将对象留给垃圾收集器,那就更容易了…

因为每个节点都有一个对其父节点的引用,我认为您可以遍历整个树,一次只在内存中保留一个节点。我在理解您的代码(特别是如何将每个节点加载到内存中)时遇到了一些困难,因此我将在伪代码中发布我的建议:

def visit(node,indent):
    # Load your node data
    print("{0} {1}".format("-" * indent, node.columns[0])) # Do something with your data
    # Unload your node data
    if len(node.children) > 0 :
        return (node.children[0], indent+1) # Visit the first child, if there is one
    while node.next is None: # If no sibling, your parent is done
        node = node.parent
        indent -= 1
        if node is None: # Root node reached, end the traversal
            return None
    return (node.next, indent) # Visit your next sibling, if there is one

cursor = (root_node, 0)
while cursor is not None:
    cursor = visit(*cursor)

如果节点本身必须动态加载(即
下一个
上一个
父节点
子节点
只包含到另一个节点数据的路径,而不包含对
节点
对象的引用),请告诉我,我将更新答案(只需要稍微更改一下加载/卸载的位置)。当然,如果卸载只是将对象留给垃圾收集器,则更容易…

正如mgibsonbr所指出的,因为您存储的是父指针,所以可以在仅跟踪当前节点(及其缩进)时迭代执行此操作:

通过将
打印
行替换为
产量缩进,节点
,可以将其转换为生成器

我不得不模拟一些测试数据来调试它。这是我的,以防其他人想玩。我认为根目录不能有同级目录(没有理由它不能有一个
next
并将数据存储在
列中,但是您希望缩进从1开始)


正如mgibsonbr所指出的,由于您存储的是父指针,因此可以在仅跟踪当前节点(及其缩进)时迭代执行此操作:

通过将
打印
行替换为
产量缩进,节点
,可以将其转换为生成器

我不得不模拟一些测试数据来调试它。这是我的,以防其他人想玩。我认为根目录不能有同级目录(没有理由它不能有一个
next
并将数据存储在
列中,但是您希望缩进从1开始)


下一个
和上一个
是什么?兄弟姐妹?你能给我们一些样本数据吗?什么是
next
prev
?兄弟姐妹?你能给我们一些示例数据吗?@jo erlend我的代码不是递归的,唯一的函数定义是
visit
,它从不调用自己。。。很抱歉,如果我误解了你的问题,当你说“我希望在内存中保留尽可能少的节点”时,我无法想象你的意思是在堆栈中。只需将这两条注释留空就可以了(因为我的代码不是递归的,在任何给定时刻堆栈中只有一个节点)。这很好!我还不太明白它是怎么工作的,但我会弄明白的。我见过的所有抽象算法都使用列表来存储要访问的节点队列,但代码中似乎不需要这样做。我真的很期待彻底的测试。谢谢!:)@jo erlend我的代码不是递归的,唯一的函数定义是
visit
,它从不调用自己。。。很抱歉,如果我误解了你的问题,当你说“我希望在内存中保留尽可能少的节点”时,我无法想象你的意思是在堆栈中。只需将这两条注释留空就可以了(因为我的代码不是递归的,在任何给定时刻堆栈中只有一个节点)。这很好!我还不太明白它是怎么工作的,但我会弄明白的。我见过的所有抽象算法都使用列表来存储要访问的节点队列,但代码中似乎不需要这样做。我真的很期待彻底的测试。谢谢!:)我喜欢这个答案,比我的更干净。但我认为最后一个
else
需要另一个
,而
-看看当父母没有兄弟姐妹,但祖父母有兄弟姐妹时会发生什么。太棒了,谢谢!)这对我来说是非常令人兴奋的,我已经在这一点上停留了一段时间,所以现在我可以有一些进步了!非常感谢:)这对我来说是一种锻炼——我总是递归地这样做。但是很有趣,谢谢你的挑战!我喜欢这个答案,比我的更干净。但我认为最后一个
else
需要另一个
,而
-看看当父母没有兄弟姐妹,但祖父母有兄弟姐妹时会发生什么。太棒了,谢谢!)这对我来说是非常令人兴奋的,我已经在这一点上停留了一段时间,所以现在我可以有一些进步了!非常感谢:)这对我来说是一种锻炼——我总是递归地这样做。但是很有趣,谢谢你的挑战!
def print_tree(from_path):

    node, indent = model.get_iter(from_path), 0

    while node:

        if indent:           # don't print the root
            print "-" * indent, node.columns[0]

        if node.children:    # walk to first child before walking to next sibling
            node = node.children[0]
            indent += 1
        elif node.next:      # no children, walk to next sibling if there is one
            node = node.next
        else:
            # no children, no more siblings: find closet ancestor w/ more siblings
            # (note that this might not be the current node's immediate parent)
            while node and not node.next:
                node = node.parent
                indent -= 1
            node = node and node.next            
class Node(object):
    def __init__(self, parent=None, sib=None, value=""):
        self.parent   = parent
        self.prev     = sib
        self.next     = None
        self.children = []
        self.columns  = [str(value)]
    def child(self, value):
        child = Node(self, None, value)
        if self.children:
            self.children[-1].next = child
            child.prev = self.children[-1]
        self.children.append(child)
        return child
    def sib(self, value):
        return self.parent.child(value)

class model(object):
    @staticmethod
    def get_iter(_):

        root = Node()

        root.child("0").child("0:0").child("0:0:0").sib("0:0:1") \
            .child("0:0:1:0").sib("0:0:1:0").parent.sib("0:0:2")
        root.children[0].child("0:1").parent.sib("1")

        return root