[Java]算术表达式组建二叉树,再由二叉树得到算式的后序和中序表达式
Entry类:
package com.hy; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; // 此类用于把算术表达式送入解析器 public class Entry { public static void main(String[] args) throws IOException{ // 取得用户输入的表达式 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String rawExpression = null; System.out.print("请输入算术表达式:"); rawExpression = br.readLine(); // 得到合法的算术表达式 String expression=""; for(int i=0;i<rawExpression.length();i++){ // 拿到表达式的每个字符 char c=rawExpression.charAt(i); //System.out.print(c+","); if(Character.isDigit(c) || c=='+' || c=='-' || c=='*' || c=='/' || c=='(' || c==')' || c=='.'){ //System.out.print(c); expression+=c; }else{ System.out.print(" "+c+"不是合法的算术表达式字符."); System.exit(0); } } // 送去解析 Lexer p=new Lexer(expression); //p.print(); // Tree t=new Tree(p.getInfixList()); try { System.out.println("算式表达式"+expression+"的计算结果为:"+t.evaluate()); System.out.println("其后序表达式为:"+t.getPostfix()); System.out.println("从二叉树重新组建的中序表达式为"+t.getInfix()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
输出如下,当然还有可以调整的地方:
请输入算术表达式:(1.1+2.3)*(3+4) 算式表达式(1.1+2.3)*(3+4)的计算结果为:23.800001 其后序表达式为:1.1 2.3 + 3.0 4.0 + * 从二叉树重新组建的中序表达式为(1.1 + 2.3 )* (3.0 + 4.0 ) 请输入算术表达式:(1+2)*3-4*(6-5) 算式表达式(1+2)*3-4*(6-5)的计算结果为:5.0 其后序表达式为:1.0 2.0 + 3.0 * 4.0 6.0 5.0 - * - 从二叉树重新组建的中序表达式为(1.0 + 2.0 )* 3.0 - 4.0 * (6.0 - 5.0 ) 请输入算术表达式:1+2*(5-4)+6-7 算式表达式1+2*(5-4)+6-7的计算结果为:2.0 其后序表达式为:1.0 2.0 5.0 4.0 - * + 6.0 + 7.0 - 从二叉树重新组建的中序表达式为((1.0 + 2.0 * (5.0 - 4.0 ))+ 6.0 )- 7.0 请输入算术表达式:1+2*(6-4) 算式表达式1+2*(6-4)的计算结果为:5.0 其后序表达式为:1.0 2.0 6.0 4.0 - * + 从二叉树重新组建的中序表达式为1.0 + 2.0 * (6.0 - 4.0 ) 请输入算术表达式:2*(3+4) 算式表达式2*(3+4)的计算结果为:14.0 其后序表达式为:2.0 3.0 4.0 + * 从二叉树重新组建的中序表达式为2.0 * (3.0 + 4.0 ) 请输入算术表达式:1*2+3*4 算式表达式1*2+3*4的计算结果为:14.0 其后序表达式为:1.0 2.0 * 3.0 4.0 * + 从二叉树重新组建的中序表达式为1.0 * 2.0 + 3.0 * 4.0 请输入算术表达式:1+2+3+4 算式表达式1+2+3+4的计算结果为:10.0 其后序表达式为:1.0 2.0 + 3.0 + 4.0 + 从二叉树重新组建的中序表达式为((1.0 + 2.0 )+ 3.0 )+ 4.0
Lexer类:
package com.hy; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; // 此类用于将算术表达式解析成包含操作数和操作符的链表,扮演分词器的角色 public class Lexer { private List<String> list;// 用于存储中序表达式的链表 public List<String> getInfixList() { return list; } public Lexer(String expression){ list=new ArrayList<String>(); // 使用正则表达式分词 String regExp = "(\\d+(\\.*)\\d*)|(\\+)|(\\-)|(\\*)|(\\/)|(\\()|(\\))"; Pattern pattern=Pattern.compile(regExp); Matcher matcher=pattern.matcher(expression); while(matcher.find()){ list.add(matcher.group(0)); } } public void print(){ for(String str:list){ System.out.println(str); } } }
Tree类:
package com.hy; import java.util.List; // 以算术表达式为基础构建一棵二叉树,它是算术表达式的语法树 public class Tree { // 根节点 private Node root; // infixList为分词完毕的中序表达式列表 public Tree(List<String> infixList){ root=build(infixList,0,infixList.size()); } // 构建一棵树,从根节点构建起 private Node build(List<String> list,int start,int end){ int depth=0;//记录深度,进一层括号加一,退出来减一 int plusDivideRightmostPos=-1;// 记录最右边的加减号位置 int multiDivideRightmostPos=-1;// 记录最右边的乘除号位置 // 操作数 if(start==end-1){ // 下标相差一,说明找到的是没有子节点的叶子节点,也即操作数节点 Node leafNode=new Node(NodeType.Digit,list.get(start)); return leafNode; } // 这个循环是为了找括号外最右边的运算符位置 for(int i=start;i<end;i++){ String operatorText=list.get(i);// 获得操作符的文字,如果是操作数直接ignore if(operatorText.equals("(")){ depth++; }else if(operatorText.equals(")")){ depth--; }else if(operatorText.equals("+") || operatorText.equals("-") ){ if(depth==0){ plusDivideRightmostPos=i; } }else if(operatorText.equals("*") || operatorText.equals("/") ){ if(depth==0){ multiDivideRightmostPos=i; } } } int rightMost=-1; if(plusDivideRightmostPos==-1 && multiDivideRightmostPos==-1){ // 整个算式被多余的括号括起来了,去掉这层多余的括号再做 return build(list,start+1,end-1); } // 优先取加减号的位置,因为它的计算优先级最低,应当最后算 rightMost=plusDivideRightmostPos; if(plusDivideRightmostPos==-1 && multiDivideRightmostPos>0){ // 括号外只有乘除号,如(1+2)*(3+4),这时只有取乘除号位置, rightMost=multiDivideRightmostPos; } // 如果能走到这里,则最右边括号外的运算符位置已经找到了,可以开始构建节点 String operator=list.get(rightMost); Node nodeOper=new Node(operator);// 这里创建的节点都是操作符节点,不是最终的叶子节点 // 以最右边的操作符为界,分两侧构建左右子节点 nodeOper.setLeftNode(build(list,start,rightMost)); nodeOper.setRightNode(build(list,rightMost+1,end)); // 返回构建完的节点 return nodeOper; } // 取二叉树的值 public float evaluate() throws Exception{ return this.root.getValue(); } // 后序遍历 private String postOrder(Node node){ if(node!=null){ String s=""; s+=postOrder(node.getLeftNode()); s+=postOrder(node.getRightNode()); s+=node.toString(); return s; } return ""; } // 从构建好的二叉树获得后序表达式 public String getPostfix(){ return postOrder(root); } // 中序遍历 private String inOrder(Node node){ if(node!=null){ String s=""; if(node.getType().equals(NodeType.OP_Plus) || node.getType().equals(NodeType.OP_Minus)){ s+="("; } s+=inOrder(node.getLeftNode()); s+=node.toString(); s+=inOrder(node.getRightNode()); if(node.getType().equals(NodeType.OP_Plus) || node.getType().equals(NodeType.OP_Minus)){ s+=")"; } return s; } return ""; } // 从构建好的二叉树获得中序表达式 public String getInfix(){ String s=""; s=inOrder(root); if(s.startsWith("(") && s.endsWith(")") && (root.getType()==NodeType.OP_Minus || root.getType()==NodeType.OP_Plus) ){ return s.substring(1, s.length()-1); }else{ return s; } } }
Node类:
package com.hy; // 二叉树节点类 public class Node { private NodeType type; private float value; private Node leftNode;// 左节点 private Node rightNode;// 右节点 public Node(){ type=NodeType.Undifined; value=0.0f; leftNode=null; rightNode=null; } public Node(String nodeTypeText){ if(nodeTypeText.equals("+")){ this.type=NodeType.OP_Plus; }else if(nodeTypeText.equals("-")){ this.type=NodeType.OP_Minus; }else if(nodeTypeText.equals("*")){ this.type=NodeType.OP_Multi; }else if(nodeTypeText.equals("/")){ this.type=NodeType.OP_Divide; }else{ this.type=NodeType.Undifined; } value=0.0f; leftNode=null; rightNode=null; } public Node(NodeType type){ this.type=type; value=0.0f; leftNode=null; rightNode=null; } public Node(NodeType type,String str){ this.type=type; this.value=Float.valueOf(str); leftNode=null; rightNode=null; } public Node(NodeType type,float value,Node leftNode,Node rightNode){ this.type=type; this.value=value; this.leftNode=leftNode; this.rightNode=rightNode; } public Node(NodeType type,Node leftNode,Node rightNode){ this.type=type; this.value=0; this.leftNode=leftNode; this.rightNode=rightNode; } public float getValue() throws Exception{ if(this.type==NodeType.Digit){ return value; }else if(this.type==NodeType.OP_Divide){ return leftNode.getValue()/rightNode.getValue(); }else if(this.type==NodeType.OP_Minus){ return leftNode.getValue()-rightNode.getValue(); }else if(this.type==NodeType.OP_Multi){ return leftNode.getValue()*rightNode.getValue(); }else if(this.type==NodeType.OP_Plus){ return leftNode.getValue()+rightNode.getValue(); }else{ throw new Exception("Not initialize"); } } public void setLeftNode(Node leftNode) { this.leftNode = leftNode; } public void setRightNode(Node rightNode) { this.rightNode = rightNode; } public Node getLeftNode() { return leftNode; } public Node getRightNode() { return rightNode; } public String toString(){ if(this.type==NodeType.Digit){ return String.valueOf(value)+" "; }else if(this.type==NodeType.OP_Divide){ return "/ "; }else if(this.type==NodeType.OP_Minus){ return "- "; }else if(this.type==NodeType.OP_Multi){ return "* "; }else if(this.type==NodeType.OP_Plus){ return "+ "; }else{ return "? "; } } public NodeType getType() { return type; } public void setType(NodeType type) { this.type = type; } public void setValue(float value) { this.value = value; } }
NodeType枚举:
package com.hy; // 节点类型 public enum NodeType { Undifined, OP_Plus, OP_Minus, OP_Multi, OP_Divide, Digit, }
--END-- 2019年9月4日15点42分
[Java]算术表达式组建二叉树,再由二叉树得到算式的后序和中序表达式的更多相关文章
- JAVA下实现二叉树的先序、中序、后序、层序遍历(递归和循环)
import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Queue; ...
- Java实现二叉树的先序、中序、后序、层序遍历(递归和非递归)
二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易 ...
- 【算法】二叉树、N叉树先序、中序、后序、BFS、DFS遍历的递归和迭代实现记录(Java版)
本文总结了刷LeetCode过程中,有关树的遍历的相关代码实现,包括了二叉树.N叉树先序.中序.后序.BFS.DFS遍历的递归和迭代实现.这也是解决树的遍历问题的固定套路. 一.二叉树的先序.中序.后 ...
- 剑指offer——已知二叉树的先序和中序排列,重构二叉树
这是剑指offer中关于二叉树重构的一道题.题目原型为: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2, ...
- C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历、中序遍历、后续遍历)
树 利用顺序存储和链式存储的特点,可以实现树的存储结构的表示,具体表示法有很多种. 1)双亲表示法:在每个结点中,附设一个指示器指示其双亲结点在数组中的位置. 2)孩子表示法:把每个结点的孩子排列起来 ...
- [LeetCode] Construct Binary Tree from Preorder and Inorder Traversal 由先序和中序遍历建立二叉树
Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume that ...
- ZT 二叉树先序,中序,后序遍历非递归实现
二叉树先序,中序,后序遍历非递归实现 分类: 数据结构及算法2012-04-28 14:30 8572人阅读 评论(6) 收藏 举报 structc 利用栈实现二叉树的先序,中序,后序遍历的非递归操作 ...
- c++实现二叉树的非递归创建以及非递归先序、中序、后序遍历
二叉树的创建 思路:数组中从上到下依次放着二叉树中的元素,使用递归很容易实现,那么这里使用容器来存放之前的状态实现循环创建二叉树. TreeNode* createTree(int *arr, int ...
- [LeetCode] 105. Construct Binary Tree from Preorder and Inorder Traversal 由先序和中序遍历建立二叉树
Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume that ...
- 左神算法基础班4_1&2实现二叉树的先序、中序、后序遍历,包括递归方式和非递归
Problem: 实现二叉树的先序.中序.后序遍历,包括递归方式和非递归方式 Solution: 切记递归规则: 先遍历根节点,然后是左孩子,右孩子, 根据不同的打印位置来确定中序.前序.后续遍历. ...
随机推荐
- 上传图片,语音,和富文本(webuploader,dropzone, froala)
首先是上传图片,使用的百度webuploader 自己修改后可以实例化多个uploader对象: HTML: <!DOCTYPE html> <html xmlns="ht ...
- Hacklab WebIDE在线调试ESP32笔记
目录 1.什么是Hacklab WebIDE 1.1 优势 1.2 趋势 2. 使用方法 2.1 功能介绍 2.2 编译第一个程序 2.3 搭建esp32的开发环境 2.4 建立开发板与云平台的连接 ...
- Java学习笔记【十三、多线程编程】
概念 Java 给多线程编程提供了内置的支持.一个多线程程序包含两个或多个能并发运行的部分.程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径. 多线程是多任务的一种特别的形式,但多线 ...
- Linux 链接脚本分析
作者:答疑助手lizuobin 原文: https://blog.csdn.net/lizuobin2/article/details/51779064 在前面学习的过程中,看代码时遇到 arch_i ...
- 第八章·Logstash深入-通过TCP/UDP收集日志
1.收集TCP/UDP日志 通过logstash的tcp/udp插件收集日志,通常用于在向elasticsearch日志补录丢失的部分日志,可以将丢失的日志通过一个TCP端口直接写入到elastics ...
- C# Winform 带水印提示输入框
using System; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms ...
- Jmeter (四) 关联
关联: 实例:关联登录请求的 session,方便下次自动登录( 自我理解) 关联用户session 关联 例如 京东秒杀 1000个用户 同时秒杀 怎么模拟?? 使用关联啊! 一.正则表达式提取器 ...
- 二进制;16进制; Byte , Python的bytes类; Base64数据编码; Bae64模块;
参考:中文维基 二进制 位操作(wiki) Byte字节 互联网数据处理:Base64数据编码 Python的模块Base64 16进制简介 python: bytes对象 字符集介绍:ascii 二 ...
- [uboot] (番外篇)uboot 驱动模型(转)重要
[uboot] uboot流程系列:[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)[project X] tiny210(s5pv210)从存储设备加载代码到D ...
- 最简单之安装hive
一,安装模式介绍 Hive官网上介绍了Hive的3种安装方式,分别对应不同的应用场景. a.内嵌模式(元数据保村在内嵌的derby种,允许一个会话链接,尝试多个会话链接时会报错) b.本地模式(本地安 ...