如何在 Python 中将二叉树打印为节点结构

2024-01-27

我有一个蟒蛇代码 https://1drv.ms/f/s!Aj9lfQS8qKqwnWiXL_t6pVaPHu0y将字符串数学表达式转换为二叉树并对树的节点进行排序,以便左子节点始终小于右子节点。我想按以下顺序打印二叉树。

例如,考虑数学表达式 ((2 * 75) / 4)。 buildParseTree() 将字符串表达式转换为树,并 printNodeInLevels() 重新排列节点,以便每个级别的左子节点都小于右子节点。操作数

  +
  /\
 4  *
    /\
   2  75

我想打印如下。我该怎么办?因为数学表达式的长度一直在变化,例如 (24 * 2)、((5 - 1) * (2 / 3))、(20 - (5 + 4)) 等

Node("+") #root
    .addkid(Node("*") #right child at level 1
        .addkid(Node("75")) #right child at level 2
        .addkid(Node("2")) #left child at level 2
            )
    .addkid(Node("4")) #left child at level 1

我已经制定了按顺序遍历模式中的级别打印节点的方法。如果我按如下方式调用该方法,它将打印以下内容:

pt = buildParseTree("( ( 2 * 74 ) / 4 )")

printNodesInLevels(pt)

output:

/ 
4 * 
2 74 

这是我创建的用于打印任何二叉树结构的函数。

它非常通用,只需要一个起始节点(根)和一个函数(或 lambda)来获取标签和左/右子节点:

您通常会在 Node 类上像这样使用它:

printBTree(rootNode,lambda n: (n.operand, n.left, n.right) )

# assuming the Node class has a string property named operand
# and left,right properties that return a Node or None

二次方程 (-b +/- sqrt(b**2 - 4*a*c))/(2*a) 可以这样打印:

#         /
#     ___/ \__
#  +/-        *
#  / \       / \
# -   sqrt  2   a
#  \     \
#   b    -
#     __/ \_
#   **      *
#  /  \    / \
# b    2  4   *
#            / \
#           a   c

这是 printBTree 函数:

import functools as fn

def printBTree(node, nodeInfo=None, inverted=False, isTop=True):

   # node value string and sub nodes
   stringValue, leftNode, rightNode = nodeInfo(node)

   stringValueWidth  = len(stringValue)

   # recurse to sub nodes to obtain line blocks on left and right
   leftTextBlock     = [] if not leftNode else printBTree(leftNode,nodeInfo,inverted,False)

   rightTextBlock    = [] if not rightNode else printBTree(rightNode,nodeInfo,inverted,False)

   # count common and maximum number of sub node lines
   commonLines       = min(len(leftTextBlock),len(rightTextBlock))
   subLevelLines     = max(len(rightTextBlock),len(leftTextBlock))

   # extend lines on shallower side to get same number of lines on both sides
   leftSubLines      = leftTextBlock  + [""] *  (subLevelLines - len(leftTextBlock))
   rightSubLines     = rightTextBlock + [""] *  (subLevelLines - len(rightTextBlock))

   # compute location of value or link bar for all left and right sub nodes
   #   * left node's value ends at line's width
   #   * right node's value starts after initial spaces
   leftLineWidths    = [ len(line) for line in leftSubLines  ]                            
   rightLineIndents  = [ len(line)-len(line.lstrip(" ")) for line in rightSubLines ]

   # top line value locations, will be used to determine position of current node & link bars
   firstLeftWidth    = (leftLineWidths   + [0])[0]  
   firstRightIndent  = (rightLineIndents + [0])[0] 

   # width of sub node link under node value (i.e. with slashes if any)
   # aims to center link bars under the value if value is wide enough
   # 
   # ValueLine:    v     vv    vvvvvv   vvvvv
   # LinkLine:    / \   /  \    /  \     / \ 
   #
   linkSpacing       = min(stringValueWidth, 2 - stringValueWidth % 2)
   leftLinkBar       = 1 if leftNode  else 0
   rightLinkBar      = 1 if rightNode else 0
   minLinkWidth      = leftLinkBar + linkSpacing + rightLinkBar
   valueOffset       = (stringValueWidth - linkSpacing) // 2

   # find optimal position for right side top node
   #   * must allow room for link bars above and between left and right top nodes
   #   * must not overlap lower level nodes on any given line (allow gap of minSpacing)
   #   * can be offset to the left if lower subNodes of right node 
   #     have no overlap with subNodes of left node                                                                                                                                 
   minSpacing        = 2
   rightNodePosition = fn.reduce(lambda r,i: max(r,i[0] + minSpacing + firstRightIndent - i[1]), \
                                 zip(leftLineWidths,rightLineIndents[0:commonLines]), \
                                 firstLeftWidth + minLinkWidth)

   # extend basic link bars (slashes) with underlines to reach left and right
   # top nodes.  
   #
   #        vvvvv
   #       __/ \__
   #      L       R
   #
   linkExtraWidth    = max(0, rightNodePosition - firstLeftWidth - minLinkWidth )
   rightLinkExtra    = linkExtraWidth // 2
   leftLinkExtra     = linkExtraWidth - rightLinkExtra

   # build value line taking into account left indent and link bar extension (on left side)
   valueIndent       = max(0, firstLeftWidth + leftLinkExtra + leftLinkBar - valueOffset)
   valueLine         = " " * max(0,valueIndent) + stringValue
   slash             = "\\" if inverted else  "/"
   backslash         = "/" if inverted else  "\\"
   uLine             = "¯" if inverted else  "_"

   # build left side of link line
   leftLink          = "" if not leftNode else ( " " * firstLeftWidth + uLine * leftLinkExtra + slash)

   # build right side of link line (includes blank spaces under top node value) 
   rightLinkOffset   = linkSpacing + valueOffset * (1 - leftLinkBar)                      
   rightLink         = "" if not rightNode else ( " " * rightLinkOffset + backslash + uLine * rightLinkExtra )

   # full link line (will be empty if there are no sub nodes)                                                                                                    
   linkLine          = leftLink + rightLink

   # will need to offset left side lines if right side sub nodes extend beyond left margin
   # can happen if left subtree is shorter (in height) than right side subtree                                                
   leftIndentWidth   = max(0,firstRightIndent - rightNodePosition) 
   leftIndent        = " " * leftIndentWidth
   indentedLeftLines = [ (leftIndent if line else "") + line for line in leftSubLines ]

   # compute distance between left and right sublines based on their value position
   # can be negative if leading spaces need to be removed from right side
   mergeOffsets      = [ len(line) for line in indentedLeftLines ]
   mergeOffsets      = [ leftIndentWidth + rightNodePosition - firstRightIndent - w for w in mergeOffsets ]
   mergeOffsets      = [ p if rightSubLines[i] else 0 for i,p in enumerate(mergeOffsets) ]

   # combine left and right lines using computed offsets
   #   * indented left sub lines
   #   * spaces between left and right lines
   #   * right sub line with extra leading blanks removed.
   mergedSubLines    = zip(range(len(mergeOffsets)), mergeOffsets, indentedLeftLines)
   mergedSubLines    = [ (i,p,line + (" " * max(0,p)) )       for i,p,line in mergedSubLines ]
   mergedSubLines    = [ line + rightSubLines[i][max(0,-p):]  for i,p,line in mergedSubLines ]                        

   # Assemble final result combining
   #  * node value string
   #  * link line (if any)
   #  * merged lines from left and right sub trees (if any)
   treeLines = [leftIndent + valueLine] + ( [] if not linkLine else [leftIndent + linkLine] ) + mergedSubLines

   # invert final result if requested
   treeLines = reversed(treeLines) if inverted and isTop else treeLines

   # return intermediate tree lines or print final result
   if isTop : print("\n".join(treeLines))
   else     : return treeLines                                       

下面是它使用简单的 TreeNode 类生成的输出类型的示例。

class TreeNode:

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

   def addValue(self,newValue):
      if newValue == self.value: return self
      if newValue < self.value:
         if self.left : return self.left.addValue(newValue)
         self.left = TreeNode(newValue)
         return self.left
      if self.right : return self.right.addValue(newValue)
      self.right = TreeNode(newValue)
      return self.right

   def printTree(self):
      printBTree(self,lambda n:(str(n.value),n.left,n.right))      

root = TreeNode(80)

root.addValue(50)
root.addValue(90)
root.addValue(10)
root.addValue(60)
root.addValue(30)
root.addValue(70)
root.addValue(55)
root.addValue(5)
root.addValue(35)
root.addValue(85)

root.printTree()

这会产生以下输出:

#              80
#          ___/  \___
#        50          90
#     __/  \__      /
#   10        60  85
#  /  \      /  \
# 5    30  55    70
#        \
#         35

该函数足够通用,可以处理未存储在对象层次结构中的二叉树结构。以下是如何使用它从包含堆树的列表中进行打印的示例:

def printHeapTree(tree, inverted=False):

    def getNode(index):
        left  = index * 2 + 1
        right = index * 2 + 2
        left  = left  if left  < len(tree) and tree[left]  else None
        right = right if right < len(tree) and tree[right] else None
        return (str(tree[index]), left, right)

    printBTree(0,getNode,inverted)


formula = ["+","4","*",None,None,"2","75"]
printHeapTree(formula)

#   +
#  / \
# 4   *
#    / \
#   2   75

该功能将自动调整较宽标签的缩进:

family = [ "Me","Paul","Rosa","Vincent","Jody","John","Kate"]
printHeapTree(family)

#                Me
#            ___/  \___
#        Paul          Rosa
#        /  \          /  \
# Vincent    Jody  John    Kate

它还可以颠倒打印树(适合家谱):

printHeapTree(family,inverted=True)

# Vincent    Jody  John    Kate
#        \  /          \  /
#        Paul          Rosa
#            ¯¯¯\  /¯¯¯
#                Me
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Python 中将二叉树打印为节点结构 的相关文章

  • Python:从javascript按钮获取下载链接

    我正在尝试让我的脚本从 www subscene com 下载字幕 问题是网页上的下载按钮是用java制作的 由于某种原因 即使我提取了URL 我也无法下载字幕 我认为这是下载按钮的代码 a class downloadLink ratin
  • 安装 Pillow 和 PIL

    I have Ubuntu 12 04 http en wikipedia org wiki List of Ubuntu releases Ubuntu 12 04 LTS 28Precise Pangolin 29 Precise Pa
  • Pandas 中的索引如何工作?

    我是Python新手 这似乎是一个需要问的基本问题 但我真的很想了解这里发生了什么 import numpy as np import pandas as pd tempdata np random random 5 myseries on
  • (Python) 我应该使用参数还是将其设为全局参数? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我有许多共享相同参数的函数 他们将多次输入和输出该参数 例如 a foo a fun a a bar a def fun a return a
  • Python:如何使用 f 字符串进行数学运算

    我正在尝试使用 python 3 6 的新 f 字符串功能编写自己的 99 瓶啤酒实现 但我被困住了 def ninety nine bottles for i in range 10 0 1 return f i bottles of b
  • Cassandra:在 session.execute() 期间“无法完成对任何主机的操作”

    卡桑德拉版本 1 2 2Thrift API 版本 19 35 0CQL支持的版本 2 0 0 3 0 1 默认 3 0 1 适用于 python 3 4 的 cassandra 驱动程序使用 sudo 运行 cassandra bin c
  • 意外的缩进错误,但缩进看起来正确

    我一直在尝试运行此代码 但它引发了缩进错误 无论我尝试什么 结果都是一样的 如果我删除之前的缩进def str self 和代码的其余部分 它工作正常 但在输出时 它不显示问题 而是显示 问题对象 def str self Indentat
  • 如何在Python中绘制“Trace Explorer”?

    我需要重新创建一个情节 踪迹浏览器 https www bupar net trace explorer html与下面在 R 中创建的类似 我希望使用 matplotlib 但找不到任何有关如何执行这样的跟踪资源管理器的示例或参考 有人能
  • 加快 pandas groupby 中的滚动总和计算

    我想按组计算大量组的滚动总和 但我很难快速地完成它 Pandas 内置了滚动和展开计算器的方法 这是一个例子 import pandas as pd import numpy as np obs per g 20 g 10000 obs g
  • 如何在pytorch中动态索引张量?

    例如 我有一个张量 tensor torch rand 12 512 768 我得到了一个索引列表 说它是 0 2 3 400 5 32 7 8 321 107 100 511 我希望从给定索引列表的维度 2 上的 512 个元素中选择 1
  • Python 的贝叶斯垃圾邮件过滤库

    我正在寻找一个可以进行贝叶斯垃圾邮件过滤的 Python 库 我查看了 SpamBayes 和 OpenBayes 但两者似乎都没有维护 我可能是错的 谁能推荐一个好的 Python 或 Clojure Common Lisp 甚至 Rub
  • 测试 python 列表的所有元素是否为 False

    如何返回False如果所有元素都在列表中False 给定的列表是 data False False False Using any https docs python org 2 library functions html any gt
  • 动态组装 Python 模块,动态导入

    我正在努力让自己熟悉importlib钩子 我想实现直接导入用其他语言编写的非Python文件并维护源映射的能力 因此提高SyntaxError带有行号的 s 仍然会给出有意义的堆栈跟踪 我加载外部文件的方法是组装 Pythonic 源代码
  • 如何使绘图的 xtick 标签成为简单的绘图?

    我不想用单词或数字作为 x 轴的刻度标签 而是想绘制一个简单的绘图 由直线和圆圈组成 作为每个 x 刻度的标签 这可能吗 如果是这样 在 matplotlib 中处理它的最佳方法是什么 我会删除刻度标签并将文本替换为patches http
  • 使用 cv2 在 python 中创建多通道零垫

    我想用 cv2 opencv 包装器在 python 中创建一个多通道 mat 对象 我在网上找到了一些例子 其中 c Mat zeros 被 numpy zeros 替换 这看起来不错 但似乎没有多通道类型适合 看代码 import cv
  • 从 Keras 检查点加载

    我正在 Keras 中训练一个模型 我使用以下代码保存了所有内容 filepath project model hdh5 checkpoint ModelCheckpoint project model hdf5 monitor loss
  • 带过滤器的 SQLAlchemy func.count

    我正在使用一个进行分页的框架 如下所示 def get count query self return self session query func count select from self model def paginate se
  • 将人员分配到床位 - 自动化方法[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我每年都会帮助举办青年营 将与会者分配到卧室是一项艰巨的任务 有 92 个卧室 活动持续一周 与会者停留的时间长短不一 而且床需要重复
  • Django ALLOWED_HOSTS 与 CORS(django-cors-headers)

    ALLOWED HOSTS 和 CORS 之间有什么区别 如果我定义了 ALLOWED HOSTS 我还需要定义 CORS 吗 我没有使用 django 模板 我也有可能动态定义这两个吗 我认为没有 我使用 django 作为后端 并在不同
  • Bokeh 中的相关图问题

    当我通过绘制数据时rect 来自 Bokeh 我在可视化中得到了一条由水平块组成的单行 数据打印正确 据我所知格式正确 type 验证它们都是列表 谁能诊断这个吗 如果问题不在这里 那么我可以附加更多代码 如果需要 在 Ubuntu 14

随机推荐