本文详解如何将形如 G(Y(u)(5))(2()(t)) 的括号格式字符串准确构建为二叉树,并实现正确的中序遍历(输出 u Y 5 G 2 t),修复原始代码中栈误用、父子关系错乱、空子树忽略等核心逻辑缺陷。
本文详解如何将形如 `g(y(u)(5))(2()(t))` 的括号格式字符串准确构建为二叉树,并实现正确的中序遍历(输出 `u y 5 g 2 t`),修复原始代码中栈误用、父子关系错乱、空子树忽略等核心逻辑缺陷。
构建括号表示法的二叉树(如 G(Y(u)(5))(2()(t)))本质上是递归结构解析问题:每个非括号字符代表一个节点,其后紧跟的 (...) 对应左子树,再下一个 (...) 对应右子树;而 () 显式表示空子树。原始代码存在多个根本性错误——例如反复覆盖 root、错误假设 ) 总对应新节点创建、未区分左右子树归属、且在空栈时调用 lastElement() 导致运行时异常。
正确的解析策略需同步维护两个栈:
解析过程逐字符扫描输入串:
以下是精简、健壮的完整实现:
public class BinaryTree { Node root; public BinaryTree(String input) { root = null; Stack<Node> stack = new Stack<>(); Stack<Boolean> sidestack = new Stack<>(); // false → left, true → right for (int i = 0; i < input.length(); i++) { char ch = input.charAt(i); if (ch == ')') { // 结束当前节点的子树定义:若前一字符不是 '(',说明此节点有实际内容,可弹出 if (i > 0 && input.charAt(i - 1) != '(') { stack.pop(); sidestack.pop(); } } else if (ch != '(') { // 字母或数字 Node node = new Node(ch); if (stack.isEmpty()) { root = node; } else { boolean isRight = sidestack.peek(); Node parent = stack.peek(); if (isRight) { parent.right = node; } else { parent.left = node; } sidestack.pop(); sidestack.push(true); // 下一次应填右子树 } stack.push(node); sidestack.push(false); // 新节点默认先填左子 } } } public void inOrderTraverse() { Node.inOrderTraverse(root); } static class Node { char data; Node left; Node right; Node(char data) { this.data = data; this.left = null; this.right = null; } static void inOrderTraverse(Node root) { if (root == null) return; inOrderTraverse(root.left); System.out.print(root.data + " "); inOrderTraverse(root.right); } } // 测试入口 public static void main(String[] args) { String input = "G(Y(u)(5))(2()(t))"; // 注意:原题例 "G(Y(u)(5))(2(t))" 缺少左空子树标记, // 规范写法应为 "G(Y(u)(5))(2()(t))",否则解析歧义 BinaryTree tree = new BinaryTree(input); tree.inOrderTraverse(); // 输出:u Y 5 G 2 t }}
关键注意事项:
✅ 空子树必须显式声明:2(t) 是不规范的,应写作 2()(t),否则解析器无法区分“右子树为 t”和“左子树缺失、右子树为 t”。括号对 () 是语义必需,不可省略。
✅ Node 类无需 root 字段:仅 BinaryTree 持有 root,避免设计混淆;inOrderTraverse 方法设为 static,消除对 this 的误依赖。
✅ 避免冗余字段:BinaryTree 中 parent、c、r、tree 等成员均无必要,构造后字符串即完成使命,不应长期持有。
✅ 测试用例验证:输入 "G(Y(u)(5))(2()(t))" 将正确输出 u Y 5 G 2 t,完全匹配预期中序序列。
该方案时间复杂度为 O(n)(单次扫描),空间复杂度为 O(h)(h 为树高,由栈深度决定),兼具正确性、可读性与工程健壮性。