[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: 切记递归规则: 先遍历根节点,然后是左孩子,右孩子, 根据不同的打印位置来确定中序.前序.后续遍历. ...
随机推荐
- spring boot 使用RedisTemplate
1导入包 <!-- redis --> <dependency> <groupId>org.springframework.boot</groupId> ...
- fastadmin html数字验证
<input id="c" name="row[q]" data-rule="required;range(0~)" class=&q ...
- Delphi 使用数据库浏览器
樊伟胜
- linux PDF转换
在libre-office以安装的情况下 soffice --convert-to pdf *.odt --invisible
- Linux 之Ubuntu在VM中安装(桌面版)
1.安装系统 https://jingyan.baidu.com/article/14bd256e0ca52ebb6d26129c.html 2.安装VM Tools https://jingyan. ...
- 使用python读取配置文件并从mysql数据库中获取数据进行传参(基于Httprunner)
最近在使用httprunner进行接口测试,在传参时,用到了三种方法:(1)从csv文件中获取:(2)在config中声名然后进行引用:(3)从函数中获取.在测试过程中,往往有些参数是需要从数据库中获 ...
- Lyft 基于 Flink 的大规模准实时数据分析平台(附FFA大会视频)
摘要:如何基于 Flink 搭建大规模准实时数据分析平台?在 Flink Forward Asia 2019 上,来自 Lyft 公司实时数据平台的徐赢博士和计算数据平台的高立博士分享了 Lyft 基 ...
- html跳转Controller的路径的问题
- 【Python之路】异步IO
线程:CPU基本执行单元,可以与同属一个进程的其他线程共享资源,线程是属于进程的. 进程:资源单元,进程一般由程序.数据集.进程控制块三部分组成.一个进程默认有一个主线程, GIL:用于在进程中对所有 ...
- MD5 加密 字符串
//获取字符串的MD5码 public string CreateMD5Hash(string input) { // Use input string to calculate MD5 hash S ...