• [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分

  • 相关阅读:
    atitit。wondows 右键菜单的管理与位置存储
    Atitit mac os 版本 新特性 attilax大总结
    Atitit。木马病毒原理机密与概论以及防御
    Atitit。木马病毒原理机密与概论以及防御
    Atitit Atitit.软件兼容性原理----------API兼容 Qa7
    Atitit Atitit.软件兼容性原理----------API兼容 Qa7
    Atitit j2ee5 jee5 j2ee6 j2ee7 jee6 jee7 新特性
    Atitit j2ee5 jee5 j2ee6 j2ee7 jee6 jee7 新特性
    mysql只显示表名和备注
    phpmyadmin 在服务起上检测到错误,请查看窗口底部
  • 原文地址:https://www.cnblogs.com/heyang78/p/11459517.html
Copyright © 2020-2023  润新知