2012-01-19 36 views
0

我有节点的树是这样的:树模型的迭代印刷

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 

但是这是它确实打印:

- 0 
-- 0:0 
-- 0:1 
-- 0 
- 1 
--- 0:0:0 
--- 0:0:1 
--- 0:0:2 
-- 0:1 
-- 0 
- 1 
--- 0:0:1 
---- 0:0:1:0 
---- 0:0:1:1 
--- 0:0:2 
-- 0 
---- 0:0:1:0 
---- 0:0:1:1 
--- 0:0:2 
---- 0:0:1:1 
---- 0: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)) 

任何帮助不胜感激。

+0

什么是'next'和'prev'?兄弟姐妹? – mgibsonbr

+0

你能给我们一些样品数据吗? – kindall

回答

2

由于每个节点有其父的引用,我想你可以遍历整个树只保留一个内存节点在同一时间。我有一点很难理解你的代码(尤其是每个节点是如何加载到内存中),所以我会后我的建议在伪代码:

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) 

如果节点本身必须动态加载(即next,prev,parentchildren只包含到另一个节点的数据的路径,而不是对一个Node对象的引用),告诉我,我会更新答案(只需要更改一些加载/卸载的地方)。当然,如果卸载只是将对象留给垃圾收集器,那更容易...

+0

@ jo-erlend我的代码不是递归的,唯一的函数定义是'visit',它从不会自动调用自己......并且对不起,如果我误解了你的问题,当你说“我想保留内存中的少数节点可能的“我无法想象你的意思**在堆栈**。只要将这两个注释留空即可(因为我的代码不是递归的,在任何给定时刻只有一个节点会在堆栈中)。 – mgibsonbr

+0

很好!我真的不明白它是如何工作的,但它确实如此,我会解决它。我见过的所有抽象算法使用列表来存储被访问节点的队列,但似乎并没有必要与您的代码。我非常期待彻底测试它。谢谢! :) –

2

由于mgibsonbr注意到,由于您正在存储父指针,因此可以在仅跟踪时进行迭代当前节点(及其缩进):

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    

可以通过用yield indent, node替换print线变成发电机此。

我不得不嘲笑了一些测试数据来调试这一点。这是我得到的,以防其他人想玩。我对待根不能够有兄弟姐妹(没有理由也不可能在一个columnsnext存储数据,但随后你会希望你的缩进从1开始)。

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 
+0

喜欢这个答案,比我的更清洁。但我认为最后一个'else'需要另一个'while' - 看看父母没有兄弟姐妹但祖父母会这样做会发生什么。 – mgibsonbr

+0

好抓,固定(我希望)。 – kindall

+0

太棒了,谢谢!:)这对我来说都非常令人兴奋,而且我一直在这一点上陷入困​​境,所以现在我可以再取得一些进展!非常感谢:) –