【Java】构建表达式二叉树和表达式二叉树求值

news/2024/11/16 19:38:37/

问题背景

1. 实现一个简单的计算器。通过键盘输入一个包含圆括号、加减乘除等符号组成的算术表达式字符串,输出该算术表达式的值。要求:

(1)系统至少能实现加、减、乘、除等运算;

(2)利用二叉树算法思想求解表达式的值,先构造由表达式构成的二叉树,按中序、后序遍历的方式输出二叉树中的结点,然后再利用通过对二叉树进行后序遍历求解算术表达式的值。

思路描述

  • 构建表达式二叉树:先用栈将算术表达式转成后缀表达式(具体思路参考),再根据后缀表达式构建表达式二叉树,构建过程:从左到右扫描后缀表达式的每个元素:如果当前元素是操作数,则创建一个只包含该操作数的节点,并将该节点压入栈中;如果当前元素是操作符,则创建一个只包含该操作符的节点,并从栈中弹出两个节点作为其左右子节点,再将该节点压入栈中。最后栈中唯一的节点即为根节点。
  • 表达式二叉树求值:后序遍历二叉树,递归计算左右子树的值,代入运算符计算

 代码实现

//二叉链表存储二叉树
public class TreeNode {String value;TreeNode left;TreeNode right;public TreeNode(String value){this.value=value;}public TreeNode(String value, TreeNode left, TreeNode right) {this.value = value;this.left = left;this.right = right;}
}
public class Calculator {private TreeNode root;public Calculator() {root = null;}public Calculator(TreeNode root) {this.root = root;}//中缀转后缀,List中每个元素就是后缀表达式中每个操作数或运算符public static List<String> infixToPostfix(String infixExpression){Stack<Character> operatorStack=new Stack<>();List<String> postfixExpression=new ArrayList<>();for(int i=0;i<infixExpression.length();i++){//如果是数字if(Character.isDigit(infixExpression.charAt(i))){//可能是多位的数StringBuilder temp=new StringBuilder();temp.append(infixExpression.charAt(i));while (++i<infixExpression.length()&&Character.isDigit(infixExpression.charAt(i))){temp.append(infixExpression.charAt(i));}postfixExpression.add(temp.toString());i--;//while判断完后,i多往后挪了一位,所以要-1}//如果是左括号else if(infixExpression.charAt(i)=='('){operatorStack.push(infixExpression.charAt(i));}//如果是右括号,去匹配左括号else if(infixExpression.charAt(i)==')'){while (!operatorStack.empty()&&operatorStack.peek()!='('){postfixExpression.add(operatorStack.pop()+"");}operatorStack.pop();}//如果是+-*/else {//将优先级<=当前运算符优先级的运算符pop出来,追加到后缀表达式中while (!operatorStack.empty()&&getPrecedence(infixExpression.charAt(i))<=getPrecedence(operatorStack.peek())){postfixExpression.add(operatorStack.pop()+"");}operatorStack.push(infixExpression.charAt(i));}}//将栈中剩余的运算符依次pop出来追加到结果中while (!operatorStack.empty()){postfixExpression.add(operatorStack.pop()+"");}return postfixExpression;}//在中缀转后缀时要判断符号优先级private static int getPrecedence(char operator) {switch (operator) {case '+':case '-':return 1;case '*':case '/':case '%':return 2;default:return 0;}}//利用后缀表达式构建表达式二叉树public static TreeNode buildExpressionTree(List<String> postfixExpression){Stack<TreeNode> stack=new Stack<>();//从左至右遍历后缀表达式for(String str:postfixExpression){//如果是运算数if(str.charAt(0)>=48&&str.charAt(0)<=57){TreeNode treeNode = new TreeNode(str, null, null);stack.push(treeNode);} else {//如果是运算符//从栈中弹出两个节点TreeNode pop1 = stack.pop();TreeNode pop2 = stack.pop();TreeNode treeNode = new TreeNode(str, pop1, pop2);stack.push(treeNode);}}//最后栈中剩余的节点就是二叉树根节点return stack.peek();}//中序遍历表达式二叉树(左根右)public static void inorderTraversal(TreeNode treeNode){if(treeNode==null)return;inorderTraversal(treeNode.left);System.out.print(treeNode.value+" ");inorderTraversal(treeNode.right);}//后序遍历表达式二叉树(左右根)public static void postorderTraversal(TreeNode treeNode){if(treeNode==null)return;postorderTraversal(treeNode.left);postorderTraversal(treeNode.right);System.out.print(treeNode.value+" ");}//后序遍历表达式二叉树求值public int evaluateExpression(){return evaluateExpression(root);}public int evaluateExpression(TreeNode root){if(root==null){return 0;}// 递归计算左右子树的值int leftValue = evaluateExpression(root.left);int rightValue = evaluateExpression(root.right);switch (root.value){case "+":return leftValue+rightValue;case "-":return leftValue-rightValue;case "*":return leftValue*rightValue;case "/":return leftValue/rightValue;default:// 如果是操作数,则返回对应的整数值return Integer.valueOf(root.value);}}
}

 运行效果

public class Main {public static void main(String[] args) {System.out.println("请输入你要计算的表达式:");Scanner sc = new Scanner(System.in);String infixExpression = sc.next();List<String> postfixExpression = Calculator.infixToPostfix(infixExpression);//中缀转后缀TreeNode binaryTree = Calculator.buildExpressionTree(postfixExpression);//利用后缀表达式构建表达式二叉树System.out.print("中序遍历:");Calculator.inorderTraversal(binaryTree);//中序遍历System.out.println();System.out.print("后序遍历:");Calculator.postorderTraversal(binaryTree);//后序遍历System.out.println();Calculator calculator = new Calculator(binaryTree);int i = calculator.evaluateExpression();System.out.println("值为:"+i);}
}

 


http://www.ppmy.cn/news/1263337.html

相关文章

【面试常考题目】五种方法解决“如何在n个无序数组中找出它的中位数(java)”问题

1.3 从N个数组中找到中位数&#xff0c;每一个数组可能乱序 在LeetCode上&#xff0c;"寻找多个数组的中位数"这类问题通常是由两个数组合并中位数问题&#xff08;即LeetCode第4题&#xff09;的变种或扩展。直接对应于多个数组合并后寻找中位数的题目在LeetCode上…

优化瑞芯微rk3566 tf卡速度uhs SDR104

环境 开发板&#xff1a;orangepi3B CPU:rk3566 TF卡速度标识&#xff1a;C10&#xff0c;U3&#xff0c;V30 起因 对于tf卡启动的系统来说&#xff0c;io会成为一个很关键的瓶颈&#xff0c;所以总希望系统能跑得快一点。我手头用的是一张金士顿的高性能tf卡&#xff0c;开…

Azure Machine Learning - 使用 Azure OpenAI 服务生成文本

使用 Azure OpenAI 服务生成文本 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕&#xff0c;复旦机器人智能实验室成员&#xff0c;阿里云认证的资深架构师&#xff0c;项目管理专业人士&…

uView框架的安装与Git管理

参考链接&#xff1a;Http请求 | uView - 多平台快速开发的UI框架 - uni-app UI框架 安装 打开我们项目的cmd进行下载&#xff1a; yarn add uview-ui 首先我们要确定&#xff0c;未下载前的文件目录以及下载后&#xff0c;是多了个文件目录node_modules 下载完成之后我们就…

麒麟v10 数据盘初始化 gpt分区

麒麟v10 数据盘初始化 gpt分区 1、查看磁盘 lsblk2 、分区 parted2.1、 设置磁盘分区形式2.2、 设置磁盘的计量单位为磁柱2.3、 分区2.4、 查看分区 3、分区格式化4、 挂载磁盘4.1、新建挂载目录4.2、挂载磁盘4.3、查看挂载结果 5、设置开机自动挂载磁盘分区5.1、 查询磁盘分区…

Java程序设计实验6 | 集合类

*本文是博主对Java各种实验的再整理与详解&#xff0c;除了代码部分和解析部分&#xff0c;一些题目还增加了拓展部分&#xff08;⭐&#xff09;。拓展部分不是实验报告中原有的内容&#xff0c;而是博主本人自己的补充&#xff0c;以方便大家额外学习、参考。 &#xff08;解…

Android studio生成二维码

1.遇到的问题 需要生成一个二维码&#xff0c;可以使用zxing第三方组件&#xff0c;增加依赖。 //生成二维码 implementation com.google.zxing:core:3.4.1 2.代码 展示页面 <ImageViewandroid:id"id/qrCodeImageView"android:layout_width"150dp"an…

Python并发-线程和进程

一、线程和进程对应的问题 **1.进程&#xff1a;**CPU密集型也叫计算密集型&#xff0c;指的是系统的硬盘、内存性能相对CPU要好很多&#xff0c;此时&#xff0c;系统运作大部分的状况是CPU Loading 100%&#xff0c;CPU要读/写I/O(硬盘/内存)&#xff0c;I/O在很短的时间就可…