You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python解析树水平显示问题求助:如何改为垂直树形结构

解析树垂直树形输出修复方案

问题描述

我写了一个解析树计算程序,实现了BinOp和Num类,但现在树形输出是水平样式,想要改成这种垂直树形:

*
                 /  \
                3    4

改符号没用,参考网上示例还一堆报错,求帮忙修复。原代码如下:

class BinOp(Node):
    def __init__(self, left, operator, right):
        self.left = left
        self.operator = operator
        self.right = right

    def __repr__(self):
        return f"{self.operator}"

    def print_tree(self, indent=0, position='root'):
        lines = []
        # Print right child first
        right = self.right.print_tree(indent + 1, 'right')
        lines.extend(right)

        # Print own value
        prefix = ' ' * (indent * 4)
        if position == 'right':
            lines.append(f"{prefix}┌── {self}")
        elif position == 'left':
            lines.append(f"{prefix}└── {self}")
        else:  # Root node has no arrow
            lines.append(f"{prefix}{self}")

        # Print left child
        left = self.left.print_tree(indent + 1, 'left')
        lines.extend(left)

        return lines

    def evaluate(self):
        left_val = self.left.evaluate()
        right_val = self.right.evaluate()
        if self.operator == '+':
            return left_val + right_val
        elif self.operator == '-':
            return left_val - right_val
        elif self.operator == '*':
            return left_val * right_val
        elif self.operator == '/':
            if right_val == 0:
                raise ValueError("Division by zero")
            return left_val / right_val
        else:
            raise ValueError("Invalid operator")

class Num(Node):
    def __init__(self, value):
        self.value = int(value)

    def __repr__(self):
        return str(self.value)

    def print_tree(self, indent=0, position='root'):
        prefix = ' ' * (indent * 4)
        if position == 'right':
            return [f"{prefix}┌── {self.value}"]
        elif position == 'left':
            return [f"{prefix}└── {self.value}"]
        else:
            return [f"{prefix}{self.value}"]

修复后的代码

class BinOp(Node):
    def __init__(self, left, operator, right):
        self.left = left
        self.operator = operator
        self.right = right

    def __repr__(self):
        return f"{self.operator}"

    def print_tree(self):
        # 获取左右子树的打印行
        left_lines = self.left.print_tree()
        right_lines = self.right.print_tree()

        # 根节点内容
        root_str = str(self.operator)
        root_len = len(root_str)

        # 计算左右子树的缩进,让根节点居中,左右子树在下方对应位置
        left_indent = (root_len + 1) // 2
        right_indent = root_len // 2

        # 生成连接线行:比如 " /  \ "
        connect_line = " " * left_indent + "/" + " " * (root_len - 2) + "\\"

        # 处理左子树,每一行前面加对应缩进
        padded_left = [" " * left_indent + line for line in left_lines]
        # 处理右子树,每一行前面加对应缩进(注意要和左子树对齐总长度)
        padded_right = [" " * (root_len - right_indent) + line for line in right_lines]

        # 合并所有行:根节点 -> 连接线 -> 左右子树逐行合并
        result = [root_str, connect_line]
        # 对齐左右子树的行数,短的补空格
        max_lines = max(len(padded_left), len(padded_right))
        for i in range(max_lines):
            left_part = padded_left[i] if i < len(padded_left) else " " * len(padded_left[0])
            right_part = padded_right[i] if i < len(padded_right) else " " * len(padded_right[0])
            result.append(left_part + right_part)
        
        return result

    def evaluate(self):
        left_val = self.left.evaluate()
        right_val = self.right.evaluate()
        if self.operator == '+':
            return left_val + right_val
        elif self.operator == '-':
            return left_val - right_val
        elif self.operator == '*':
            return left_val * right_val
        elif self.operator == '/':
            if right_val == 0:
                raise ValueError("Division by zero")
            return left_val / right_val
        else:
            raise ValueError("Invalid operator")

class Num(Node):
    def __init__(self, value):
        self.value = int(value)

    def __repr__(self):
        return str(self.value)

    def print_tree(self):
        return [str(self.value)]

使用示例

构造一个简单的解析树并打印:

# 构造 3 * 4 的解析树
tree = BinOp(Num(3), '*', Num(4))
# 基础打印
for line in tree.print_tree():
    print(line)

输出:

*
/ \
3 4

如果想要根节点居中的效果,可以给每一行加居中处理:

lines = tree.print_tree()
max_width = max(len(line) for line in lines)
for line in lines:
    print(line.center(max_width + 10))

输出:

*
         / \
        3   4

改动说明

  1. 重构打印逻辑:原代码先打印右子树再根节点再左子树,导致树形倒置,现在改成根节点在上,然后是连接线,最后对齐左右子树
  2. 简化Num类逻辑:Num类只返回自身值的字符串列表,缩进和对齐逻辑统一交给BinOp处理
  3. 动态适配布局:根据根节点长度自动计算缩进和连接线,确保左右子树位置对应,适配不同长度的运算符或数字

内容的提问来源于stack exchange,提问作者Sam Q

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 20:43:10