逆波兰表达式与表达式求值

昨天复习栈和队列的时候看到了逆波兰表达式,虽然之前有所学习,但是并没有动手实践,今天用Java实践了一下。
里面用到了栈和队列,顺便总结下栈和队列。

队列
Java对象 Stack Queue
特征 先进后出,后进先出 先进先出,后进后出
push(obj) offer(obj)
peek() peek()
pop() poll()
是否为空 empty() size()==0

感觉比较有趣,相当于做了一个简易版科学计算器。

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

//表达式对象
public class Expression {
    private int index = 0;//表达式读取下标
    private String expression;//表达式

    public Expression(String expression) {
        this.expression = expression;
    }

    /**
     * 转为逆波兰表达式
     * 例如:中缀表达式:1+2*3+(4*5+6)/7
     * 转为:后缀表达式:123*+45*6+7/+
     * @return 逆波兰(后缀)表达式队列
     */
    public Queue<?> toRPN(){
        resetIndex();
        Queue<Object> rpn = new LinkedList<>();
        Stack<Operator> opStatck = new Stack<>();
        rpn.offer((double) 0);//先默认添加一个0,避免-(-2)这种情况出错,变为0-(-2)
        while(hasNext()){
            Object next = next();//从中缀表达式中读取一个
            if(next instanceof Double){//读到的是操作数
                rpn.offer(next);//push到rpn
            }
            else{//读到的是符号
                Operator op = Operator.valueOf((Character) next);//转为相应操作符对象
                OP:while(!opStatck.empty()) {
                    Operator first = opStatck.peek();
                    if(op.equals(Operator.RIGHT_PAR)){//如果读到的是),需要把操作符逐个弹出,直到遇到(
                        while(!opStatck.empty()){
                            first = opStatck.pop();//弹出一个操作符
                            if(first.equals(Operator.LEFT_PAR)){
                                break OP;
                            }
                            rpn.offer(first);//把弹出的操作符(右括号除外)送入rpn
                        }
                    }
                    else if(first.equals(Operator.LEFT_PAR)){
                        break;
                    }
                    else if(first.getPriority()>=op.getPriority()){
                        rpn.offer(opStatck.pop());
                    }
                    else{
                        break;
                    }
                }
                if(!op.equals(Operator.RIGHT_PAR))
                    opStatck.push(op);
            }
        }
        while(!opStatck.empty()){//把操作符栈中所有操作符出栈并写到rpn队列里
            rpn.offer(opStatck.pop());
        }
        return rpn;
    }

    /**
     * 计算表达式的值
     * @return 计算结果
     */

    public double calculate(){
        Queue<?> rpn = toRPN();//先求出逆波兰表达式
        Stack<Object> stack = new Stack<>();
        while(rpn.size()>0){
            Object op = rpn.poll();//取出一个操作
            if(op instanceof Double){//如果是操作数
                stack.push(op);//操作数入栈
            }
            else{//如果是操作符
                Operator operator = (Operator) op;
                double[] numbers = new double[operator.getFactor()];//计算是几元操作符,并从栈中弹出相应个数的操作数
                for(int i =operator.getFactor()-1;i>=0;i--){
                    numbers[i] = (double) stack.pop();
                }
                double value = operator.calculator(numbers);//计算求值
                stack.push(value);//把值送入栈
            }
        }
        return (double) stack.pop();//最后栈顶的操作数就是运算结果了
    }

    /**
     * 从中缀表达式读取下一个操作(可能读到操作符也可能读操作数)。
     * @return 读到的操作
     */
    public Object next(){
        char[] chars = expression.toCharArray();
        chars = Arrays.copyOfRange(chars, index, chars.length);
        String reg = "^-?\\d+\\.?\\d*";//匹配数字的正则表达式
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(String.valueOf(chars));
        boolean found = matcher.find();
        Object result;
        if(found){//找到了数字,匹配数字
            String first = matcher.group(0);
            result = Double.valueOf(first);
            index += first.length();
        }
        else{//匹配一个操作符
            result = chars[0];
            index ++;
        }
        return result;
    }


    /**
     * @return 是否有下一个操作
     */
    public boolean hasNext(){
        return index<expression.length();
    }

    /**
     * 重置操作读取下标
     */
    public void resetIndex(){
        this.index = 0;
    }

    /**
     * 操作符对象
     */
    static abstract class Operator{
        private char operator;//符号
        private int priority;//计算优先级
        private int factor;//操作数个数

        //加
        public static Operator PLUS = new Operator('+', 1, 2) {
            @Override
            public double calculator(double[] numbers) {
                return numbers[0] + numbers[1];
            }
        };

        //减
        public static Operator SUB = new Operator('-', 1, 2) {
            @Override
            public double calculator(double[] numbers) {
                return numbers[0] - numbers[1];
            }
        };

        //乘
        public static Operator MUL = new Operator('*', 2, 2) {
            @Override
            public double calculator(double[] numbers) {
                return numbers[0] * numbers[1];
            }
        };

        //除
        public static Operator DIV = new Operator('/', 2, 2) {
            @Override
            public double calculator(double[] numbers) {
                return numbers[0] / numbers[1];
            }
        };

        //幂
        public static Operator POW = new Operator('^', 3, 2) {
            @Override
            public double calculator(double[] numbers) {
                return Math.pow(numbers[0],numbers[1]);
            }
        };

        //左括号
        public static Operator LEFT_PAR = new Operator('(', 100, 0) {
            @Override
            public double calculator(double[] numbers) {
               return 0;
            }
        };

        //右括号
        public static Operator RIGHT_PAR = new Operator(')', 100, 0) {
            @Override
            public double calculator(double[] numbers) {
                return 0;
            }
        };

        //所有操作符列表
        public static Operator[] ALL ={PLUS,SUB,MUL,DIV,POW,LEFT_PAR,RIGHT_PAR};

        public Operator(char operator, int priority,int factor) {
            this.operator = operator;
            this.priority = priority;
            this.factor = factor;
        }

        public char getOperator() {
            return operator;
        }

        public void setOperator(char operator) {
            this.operator = operator;
        }

        public int getPriority() {
            return priority;
        }

        public void setPriority(int priority) {
            this.priority = priority;
        }

        public int getFactor() {
            return factor;
        }

        public void setFactor(int factor) {
            this.factor = factor;
        }

        //计算值
        public abstract double calculator(double[] numbers);

        //根据操作符字符获取操作符对象
        public static Operator valueOf(char operator){
            for(Operator op:Operator.ALL){
                if(op.getOperator()==operator){
                    return op;
                }
            }
            return null;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Operator operator1 = (Operator) o;
            return operator == operator1.operator;
        }

        @Override
        public int hashCode() {
            return Objects.hash(operator);
        }

        @Override
        public String toString() {
            return String.valueOf(operator);
        }
    }

    public static void main(String[] args) {
        String exp = "1024/16*3-(135+415)/5+16";
        Expression expression = new Expression(exp);//创建表达式对象
        double value = expression.calculate();//计算求值
        System.out.println(value);//打印值
    }
}

评论

  1. 4月前
    2021-4-04 22:00:31

    你好

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇