【问题标题】:print binary tree level by level in python在python中逐级打印二叉树
【发布时间】:2022-04-11 20:06:25
【问题描述】:

我想按以下方式打印我的二叉树:

                   10

               6        12

             5   7    11  13 

我已经编写了用于插入节点的代码,但无法编写用于打印树的代码。所以请帮忙。我的代码是:

class Node:
    def __init__(self,data):
       self.data=data
       self.left=None
       self.right=None
       self.parent=None

class binarytree:
   def __init__(self):
     self.root=None
     self.size=0

   def insert(self,data):
     if self.root==None:
        self.root=Node(data)

    else:
        current=self.root
        while 1:
            if data < current.data:
                if current.left:
                    current=current.left
                else:
                    new=Node(data)
                    current.left=new
                    break;
            elif data > current.data:
                if current.right:
                    current=current.right
                else:
                    new=Node(data)
                    current.right=new
                    break;
            else:
                break



 b=binarytree()  

【问题讨论】:

  • 您可以向您的 Node 类添加一个方法,该方法计算您在获得 None 或您的根之前可以返回父级的次数。
  • Just FYSA 在 BASH 中,我使用 .txt 文件方法并尝试从此处的任何根节点打印相同的内容:stackoverflow.com/a/67341334/1499296

标签: python python-3.4


【解决方案1】:

这是我的尝试,使用递归,并跟踪每个节点的大小和子节点的大小。

class BstNode:

    def __init__(self, key):
        self.key = key
        self.right = None
        self.left = None

    def insert(self, key):
        if self.key == key:
            return
        elif self.key < key:
            if self.right is None:
                self.right = BstNode(key)
            else:
                self.right.insert(key)
        else: # self.key > key
            if self.left is None:
                self.left = BstNode(key)
            else:
                self.left.insert(key)

    def display(self):
        lines, *_ = self._display_aux()
        for line in lines:
            print(line)

    def _display_aux(self):
        """Returns list of strings, width, height, and horizontal coordinate of the root."""
        # No child.
        if self.right is None and self.left is None:
            line = '%s' % self.key
            width = len(line)
            height = 1
            middle = width // 2
            return [line], width, height, middle

        # Only left child.
        if self.right is None:
            lines, n, p, x = self.left._display_aux()
            s = '%s' % self.key
            u = len(s)
            first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s
            second_line = x * ' ' + '/' + (n - x - 1 + u) * ' '
            shifted_lines = [line + u * ' ' for line in lines]
            return [first_line, second_line] + shifted_lines, n + u, p + 2, n + u // 2

        # Only right child.
        if self.left is None:
            lines, n, p, x = self.right._display_aux()
            s = '%s' % self.key
            u = len(s)
            first_line = s + x * '_' + (n - x) * ' '
            second_line = (u + x) * ' ' + '\\' + (n - x - 1) * ' '
            shifted_lines = [u * ' ' + line for line in lines]
            return [first_line, second_line] + shifted_lines, n + u, p + 2, u // 2

        # Two children.
        left, n, p, x = self.left._display_aux()
        right, m, q, y = self.right._display_aux()
        s = '%s' % self.key
        u = len(s)
        first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s + y * '_' + (m - y) * ' '
        second_line = x * ' ' + '/' + (n - x - 1 + u + y) * ' ' + '\\' + (m - y - 1) * ' '
        if p < q:
            left += [n * ' '] * (q - p)
        elif q < p:
            right += [m * ' '] * (p - q)
        zipped_lines = zip(left, right)
        lines = [first_line, second_line] + [a + u * ' ' + b for a, b in zipped_lines]
        return lines, n + m + u, max(p, q) + 2, n + u // 2


import random

b = BstNode(50)
for _ in range(50):
    b.insert(random.randint(0, 100))
b.display()

示例输出:

                              __50_________________________________________ 
                             /                                             \
    ________________________43_                   ________________________99
   /                           \                 /                          
  _9_                         48    ____________67_____________________     
 /   \                             /                                   \    
 3  11_________                   54___                         ______96_   
/ \            \                       \                       /         \  
0 8       ____26___________           61___           ________88___     97  
         /                 \         /     \         /             \        
        14_             __42        56    64_       75_____       92_       
       /   \           /                 /   \     /       \     /   \      
      13  16_         33_               63  65_   72      81_   90  94      
             \       /   \                     \         /   \              
            25    __31  41                    66        80  87              
                 /                                     /                    
                28_                                   76                    
                   \                                                        
                  29                                                        

【讨论】:

  • 但是,它不能显示已经创建的BT,对吗?即使使用 'insert()' 函数,新节点也会根据它们的值插入,而不是像人们想要的那样。
  • @Apostolos 不确定我是否理解您的评论。还想怎么插入节点?
  • 示例:一个BT设置如下:tree = (50, (30, (20, (10, None, None), None), (40, None, None)), (80, (70, (60, None, (61, None, (62, None, None))), None), (90, None, None)))。它是完全定义的,即孩子的所有左右位置都已设置(即使是空的)。此设置对您有意义吗?
  • 树形结构取决于您添加元素的顺序,但在您的情况下,如果您按照列出它们的方式添加它们,您将得到您想要的:b = BstNode(50); for n in (30, 20, 10, 40, 80, 70, 60, 61, 62, 90): b.insert(n); b.display()
  • 当然它不会显示None,但你可以修改_display_aux来显示它,如果这是你想要的
【解决方案2】:

您要查找的是breadth-first traversal,它可以让您逐级遍历树。基本上,您使用队列来跟踪您需要访问的节点,将子节点添加到队列的 back 中(而不是将它们添加到 front 堆栈)。先搞定它。

完成此操作后,您可以计算出树有多少层 (log2(node_count) + 1) 并使用它来估计空白。如果您想获得完全正确的空白,您可以使用其他数据结构来跟踪每个级别需要多少空间。不过,使用节点和级别的数量进行智能估计就足够了。

【讨论】:

    【解决方案3】:
    class Node(object):
        def __init__(self, value, left=None, right=None):
            self.value = value
            self.left = left
            self.right = right
        
    def printTree(node, level=0):
        if node != None:
            printTree(node.left, level + 1)
            print(' ' * 4 * level + '-> ' + node.value)
            printTree(node.right, level + 1)
    
    t = Node(1, Node(2, Node(4, Node(7)),Node(9)), Node(3, Node(5), Node(6)))
    printTree(t)
    

    输出:

                -> 7
            -> 4
        -> 2
            -> 9
    -> 1
            -> 5
        -> 3
            -> 6
    

    【讨论】:

    • 从递归调用切换左右节点后,我能够更好地表示树(顺时针旋转 90 度后)。这是我打印和显示树的最佳快捷方式。
    【解决方案4】:

    我将在这里留下一个独立版本的@J。 V.的代码。如果有人想获取他/她自己的二叉树并漂亮地打印出来,传递根节点就可以了。

    如有必要,请根据您的节点定义更改valleftright 参数。

    def print_tree(root, val="val", left="left", right="right"):
        def display(root, val=val, left=left, right=right):
            """Returns list of strings, width, height, and horizontal coordinate of the root."""
            # No child.
            if getattr(root, right) is None and getattr(root, left) is None:
                line = '%s' % getattr(root, val)
                width = len(line)
                height = 1
                middle = width // 2
                return [line], width, height, middle
    
            # Only left child.
            if getattr(root, right) is None:
                lines, n, p, x = display(getattr(root, left))
                s = '%s' % getattr(root, val)
                u = len(s)
                first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s
                second_line = x * ' ' + '/' + (n - x - 1 + u) * ' '
                shifted_lines = [line + u * ' ' for line in lines]
                return [first_line, second_line] + shifted_lines, n + u, p + 2, n + u // 2
    
            # Only right child.
            if getattr(root, left) is None:
                lines, n, p, x = display(getattr(root, right))
                s = '%s' % getattr(root, val)
                u = len(s)
                first_line = s + x * '_' + (n - x) * ' '
                second_line = (u + x) * ' ' + '\\' + (n - x - 1) * ' '
                shifted_lines = [u * ' ' + line for line in lines]
                return [first_line, second_line] + shifted_lines, n + u, p + 2, u // 2
    
            # Two children.
            left, n, p, x = display(getattr(root, left))
            right, m, q, y = display(getattr(root, right))
            s = '%s' % getattr(root, val)
            u = len(s)
            first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s + y * '_' + (m - y) * ' '
            second_line = x * ' ' + '/' + (n - x - 1 + u + y) * ' ' + '\\' + (m - y - 1) * ' '
            if p < q:
                left += [n * ' '] * (q - p)
            elif q < p:
                right += [m * ' '] * (p - q)
            zipped_lines = zip(left, right)
            lines = [first_line, second_line] + [a + u * ' ' + b for a, b in zipped_lines]
            return lines, n + m + u, max(p, q) + 2, n + u // 2
    
        lines, *_ = display(root, val, left, right)
        for line in lines:
            print(line)
    

    print_tree(root)
    
              __7 
             /   \
         ___10_  3
        /      \  
      _19     13  
     /   \        
     9   8_       
    / \    \      
    4 0   12 
    

    【讨论】:

    • 干得好!但是,您的 display() 参数中有一个错误。应该是这样的:python def print_tree(root, val="val", left="left", right="right"): def display(root, val=val, left=left, right=right):
    • @BcK 嗨,我刚刚找到了你的打印定义,因为我也必须实现这种打印,但是我在更改参数时遇到了问题 - 你说我们会处理 @ 987654328@ 和 right 但我不知道要改什么。你能在空闲时间检查一下吗?:stackoverflow.com/questions/67530220/…
    【解决方案5】:

    我增强了Prashant Shukla answer 以在同一行中打印同一级别的节点,不带空格。

    class Node(object):
        def __init__(self, value, left=None, right=None):
            self.value = value
            self.left = left
            self.right = right
    
        def __str__(self):
            return str(self.value)
    
    
    def traverse(root):
        current_level = [root]
        while current_level:
            print(' '.join(str(node) for node in current_level))
            next_level = list()
            for n in current_level:
                if n.left:
                    next_level.append(n.left)
                if n.right:
                    next_level.append(n.right)
            current_level = next_level
    
    t = Node(1, Node(2, Node(4, Node(7)), Node(9)), Node(3, Node(5), Node(6)))
    
    traverse(t)
    

    【讨论】:

    • 我对@9​​87654323@ 被for 循环覆盖current_level 的元素感到困惑!你能解释一下这段代码是如何工作的吗?
    【解决方案6】:

    只需使用 print2DTree 这个小方法:

    class bst:
        def __init__(self, value):
            self.value = value
            self.right = None
            self.left = None
            
    def insert(root, key):
        if not root:
            return bst(key)
        if key >= root.value:
            root.right = insert(root.right, key)
        elif key < root.value:
            root.left = insert(root.left, key)
        return root
    
    def insert_values(root, values):
        for value in values:
            root = insert(root, value)
        return root
    
    def print2DTree(root, space=0, LEVEL_SPACE = 5):
        if (root == None): return
        space += LEVEL_SPACE
        print2DTree(root.right, space)
        # print() # neighbor space
        for i in range(LEVEL_SPACE, space): print(end = " ")  
        print("|" + str(root.value) + "|<")
        print2DTree(root.left, space)
    
    root = insert_values(None, [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15])
    print2DTree(root)  
    

    结果:

    【讨论】:

      【解决方案7】:

      代码说明:

      • 通过使用 BFS 获取列表的列表包含每个级别的元素
      • 任何级别的空格数 =(树中的最大元素数)//2^level
      • h高度树的最大元素个数=2^h -1;考虑根级高度为 1
      • 打印值和空格 在这里找到我的 Riple.it 链接print-bst-tree
      def bfs(node,level=0,res=[]):
        if level<len(res):
          if node:
            res[level].append(node.value)
          else:
            res[level].append(" ")
        else:
          if node:
            res.append([node.value])
          else:
            res.append([" "])
        if not node:
          return 
        bfs(node.left,level+1,res)
        bfs(node.right,level+1,res)
        return res
          
      def printTree(node):
        treeArray = bfs(node)
        h = len(treeArray)
        whiteSpaces = (2**h)-1
        
        def printSpaces(n):
          for i in range(n):
            print(" ",end="")
      
            
        for level in treeArray:
          whiteSpaces = whiteSpaces//2
          for i,x in enumerate(level):
            if i==0:
              printSpaces(whiteSpaces)
            print(x,end="")
            printSpaces(1+2*whiteSpaces)
          print()
      #driver Code
      printTree(root)
      

      #输出

      【讨论】:

        【解决方案8】:

        here 正在回答类似的问题,这可能有助于以下代码以这种格式打印

        >>> 
        1
        2 3
        4 5 6
        7
        >>> 
        

        代码如下:

        class Node(object):
          def __init__(self, value, left=None, right=None):
           self.value = value
           self.left = left
           self.right = right
        
        def traverse(rootnode):
          thislevel = [rootnode]
          a = '                                 '
          while thislevel:
            nextlevel = list()
            a = a[:len(a)/2]
            for n in thislevel:
              print a+str(n.value),
              if n.left: nextlevel.append(n.left)
              if n.right: nextlevel.append(n.right)
              print
              thislevel = nextlevel
        
        t = Node(1, Node(2, Node(4, Node(7)),Node(9)), Node(3, Node(5), Node(6)))
        
        traverse(t)
        

        编辑后的代码以这种格式给出结果:

        >>> 
                      1
              2         3
          4     9     5     6
        7
        >>> 
        

        这只是一种技巧,可以做你想做的事,他们可能是一种合适的方法,我建议你深入研究它。

        【讨论】:

        • 感谢您的回答,但我想以我上面指定的格式打印我的树(层次结构)
        • 我已经编辑了我原来的答案,希望这能解决你的目的。
        • 这是一个复制粘贴的答案from the linked question,它甚至不能用 Python 编译,因为它是用 C 语言编写的。被否决了。
        【解决方案9】:
        class magictree:
            def __init__(self, parent=None):
                self.parent = parent
                self.level = 0 if parent is None else parent.level + 1
                self.attr = []
                self.rows = []
        
            def add(self, value):
                tr = magictree(self)
                tr.attr.append(value)
                self.rows.append(tr)
                return tr
        
            def printtree(self):
                def printrows(rows):
                    for i in rows:
                        print("{}{}".format(i.level * "\t", i.attr))
                        printrows(i.rows)
        
                printrows(self.rows)
        
        tree = magictree()
        group = tree.add("company_1")
        group.add("emp_1")
        group.add("emp_2")
        emp_3 = group.add("emp_3")
        
        group = tree.add("company_2")
        group.add("emp_5")
        group.add("emp_6")
        group.add("emp_7")
        
        emp_3.add("pencil")
        emp_3.add("pan")
        emp_3.add("scotch")
        
        tree.printtree()
        

        结果:

        ['company_1']
            ['emp_1']
            ['emp_2']
            ['emp_3']
                ['pencil']
                ['pan']
                ['scotch']
        ['company_2']
            ['emp_5']
            ['emp_6']
            ['emp_7']
        

        【讨论】:

          【解决方案10】:

          当我从 Google 提出这个问题时(我敢打赌其他许多人也这样做了),这里是具有多个子节点的二叉树,具有打印功能(__str__ 在执行 str(object_var)print(object_var) 时被调用)。

          代码:

          from typing import Union, Any
          
          class Node:
              def __init__(self, data: Any):
                  self.data: Any = data
                  self.children: list = []
              
              def insert(self, data: Any):
                  self.children.append(Node(data))
          
              def __str__(self, top: bool=True) -> str:
                  lines: list = []
                  lines.append(str(self.data))
                  for child in self.children:
                      for index, data in enumerate(child.__str__(top=False).split("\n")):
                          data = str(data)
                          space_after_line = "   " * index
                          if len(lines)-1 > index:
                              lines[index+1] += "   " + data
                              if top:
                                  lines[index+1] += space_after_line
                          else:
                              if top:
                                  lines.append(data + space_after_line)
                              else:
                                  lines.append(data)
                          for line_number in range(1, len(lines) - 1):
                              if len(lines[line_number + 1]) > len(lines[line_number]):
                                  lines[line_number] += " " * (len(lines[line_number + 1]) - len(lines[line_number]))
          
                  lines[0] = " " * int((len(max(lines, key=len)) - len(str(self.data))) / 2) + lines[0]
                  return '\n'.join(lines)
          
              def hasChildren(self) -> bool:
                  return bool(self.children)
          
              def __getitem__(self, pos: Union[int, slice]):
                  return self.children[pos]
          

          然后是演示:

          # Demo
          root = Node("Languages Good For")
          root.insert("Serverside Web Development")
          root.insert("Clientside Web Development")
          root.insert("For Speed")
          root.insert("Game Development")
          root[0].insert("Python")
          root[0].insert("NodeJS")
          root[0].insert("Ruby")
          root[0].insert("PHP")
          root[1].insert("CSS + HTML + Javascript")
          root[1].insert("Typescript")
          root[1].insert("SASS")
          root[2].insert("C")
          root[2].insert("C++")
          root[2].insert("Java")
          root[2].insert("C#")
          root[3].insert("C#")
          root[3].insert("C++")
          root[0][0].insert("Flask")
          root[0][0].insert("Django")
          root[0][1].insert("Express")
          root[0][2].insert("Ruby on Rails")
          root[0][0][0].insert(1.1)
          root[0][0][0].insert(2.1)
          print(root)
          

          【讨论】:

            【解决方案11】:

            这是我自己的 BST 实现的一部分。这个问题的丑陋部分是你必须知道你的孩子占据的空间,然后才能打印出自己。因为你可以有非常大的数字,比如 217348746327642386478832541267836128736...,也可以有像 10 这样的小数字,所以如果你在这两者之间有亲子关系,那么它可能会与你的另一个孩子重叠。因此,我们需要先通过孩子,确保我们得到他们有多少空间,然后我们使用这些信息来构建我们自己。

            def __str__(self):
                h = self.getHeight()
                rowsStrs = ["" for i in range(2 * h - 1)]
                
                # return of helper is [leftLen, curLen, rightLen] where
                #   leftLen = children length of left side
                #   curLen = length of keyStr + length of "_" from both left side and right side
                #   rightLen = children length of right side.
                # But the point of helper is to construct rowsStrs so we get the representation
                # of this BST.
                def helper(node, curRow, curCol):
                    if(not node): return [0, 0, 0]
                    keyStr = str(node.key)
                    keyStrLen = len(keyStr)
                    l = helper(node.l, curRow + 2, curCol)
                    rowsStrs[curRow] += (curCol -len(rowsStrs[curRow]) + l[0] + l[1] + 1) * " " + keyStr
                    if(keyStrLen < l[2] and (node.r or (node.p and node.p.l == node))): 
                        rowsStrs[curRow] += (l[2] - keyStrLen) * "_"
                    if(l[1]): 
                        rowsStrs[curRow + 1] += (len(rowsStrs[curRow + 2]) - len(rowsStrs[curRow + 1])) * " " + "/"
                    r = helper(node.r, curRow + 2, len(rowsStrs[curRow]) + 1)
                    rowsStrs[curRow] += r[0] * "_"
                    if(r[1]): 
                        rowsStrs[curRow + 1] += (len(rowsStrs[curRow]) - len(rowsStrs[curRow + 1])) * " " + "\\"
                    return [l[0] + l[1] + 1, max(l[2] - keyStrLen, 0) + keyStrLen + r[0], r[1] + r[2] + 1]
            
                helper(self.head, 0, 0)
                res = "\n".join(rowsStrs)
                #print("\n\n\nStart of BST:****************************************")
                #print(res)
                #print("End of BST:****************************************")
                #print("BST height: ", h, ", BST size: ", self.size)
            
                return res
            

            以下是一些运行示例:

            [26883404633, 10850198033, 89739221773, 65799970852, 6118714998, 31883432186, 84275473611, 25958013736, 92141734773, 91725885198, 131191476, 81453208197, 41559969292, 90704113213, 6886252839]
                                                 26883404633___________________________________________
                                                /                                                      \
                                   10850198033__                                                        89739221773___________________________
                                  /             \                                                      /                                      \
                       6118714998_               25958013736                 65799970852_______________                                        92141734773
                      /           \                                         /                          \                                      /
             131191476             6886252839                   31883432186_                            84275473611                91725885198
                                                                            \                          /                          /
                                                                             41559969292    81453208197                90704113213
            

            另一个例子:

            ['rtqejfxpwmggfro', 'viwmdmpedzwvvxalr', 'mvvjmkdcdpcfb', 'ykqehfqbpcjfd', 'iuuujkmdcle', 'nzjbyuvlodahlpozxsc', 'wdjtqoygcgbt', 'aejduciizj', 'gzcllygjekujzcovv', 'naeivrsrfhzzfuirq', 'lwhcjbmcfmrsnwflezxx', 'gjdxphkpfmr', 'nartcxpqqongr', 'pzstcbohbrb', 'ykcvidwmouiuz']
                                                                                                     rtqejfxpwmggfro____________________
                                                                                                    /                                   \
                                                          mvvjmkdcdpcfb_____________________________                                     viwmdmpedzwvvxalr_______________
                                                         /                                          \                                                                    \
                                     iuuujkmdcle_________                                            nzjbyuvlodahlpozxsc_                                                 ykqehfqbpcjfd
                                    /                    \                                          /                    \                                               /
             aejduciizj_____________                      lwhcjbmcfmrsnwflezxx    naeivrsrfhzzfuirq_                      pzstcbohbrb                       wdjtqoygcgbt_
                                    \                                                               \                                                                    \
                                     gzcllygjekujzcovv                                               nartcxpqqongr                                                        ykcvidwmouiuz
                                    /
                         gjdxphkpfmr
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-04-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-11-09
              • 1970-01-01
              相关资源
              最近更新 更多