• 使用栈结构计算中缀表达式


    栈中元素的顺序是先进后出,添加的元素总在栈顶,出栈也是先出栈顶,就像弹夹一样。中缀表达式是我们人计算表达式的方式例如 (2*3-2)*(3+3*3)我们总会括号优先,* / 优先于+ -

    使用栈结构计算这个表达式的核心思想就是搞两个栈,一个存放数字,一个存放符号。

    package com.dfsn.cloud.eureka;
    
    public class Stack<T> {
    
        private Object arr[];
    
        private int top = -1;
    
        public Stack(int capacity) {
            arr = new Object[capacity];
        }
    
        public void push(T t) {
            if (isFull()) {
                throw new RuntimeException("栈已满,无法添加");
            }
            top++;
            arr[top] = t;
        }
    
        public T pop() {
            if (isEmpty()) {
                throw new RuntimeException("栈为空,没有元素");
            }
            return (T) arr[top--];
        }
    
        public T peek() {
            if (isEmpty()) {
                throw new RuntimeException("栈为空,没有元素");
            }
            return (T) arr[top];
        }
    
        public boolean isEmpty() {
            return top == -1;
        }
    
        public boolean isFull() {
            return top == arr.length - 1;
        }
    
        public void show() {
            for (int i = 0; i <= top; i++) {
                System.out.println(arr[i]);
            }
        }
    
        public int size() {
            return top + 1;
        }
    
    }
    View Code
    package com.dfsn.cloud.eureka;
    
    //中缀表达式
    public class NifixExpression {
    
        public int calculate(String expression) {
    
            // 限定最多10个数字
            Stack<Integer> numberStack = new Stack<>(10);
            // 10个数字需要9个字符
            Stack<String> symbolStack = new Stack<>(9);
    
            for (int i = 0; i < expression.length(); i++) {
                String current = expression.substring(i, i + 1);
                // 是数字还是字符
                int symbolOrNumber = symbolOrNumber(current);
                // 是数字
                if (symbolOrNumber == 0) {
                    // 如果是数字,则需要判断后边的是不是数字,防止多位数
                    int concatNumber = concatNumber(expression.substring(i));
                    // 如果是多位数循环需要跳过比如 123+2
                    // 取出123 后下一个要取 + 也就是 i+(123.length),但循环本身会自增1所以只能+123.length-1
                    i += (concatNumber + "").length() - 1;
                    // 入数字栈
                    numberStack.push(concatNumber);
                } else {// 是符号
                    if (symbolStack.isEmpty()) {
                        // 符号栈没有符号,则入栈
                        symbolStack.push(current);
                    } else {
                        // 如果是左括号直接入栈
                        if (current.equals("(")) {
                            symbolStack.push(current);
                            continue;
                        }
                        // 如果是右括号,则需要每次弹出一个符号和两个数字做运算
                        // 直到碰到 ( 符号结束,并把 ( 出栈
                        if (current.equals(")")) {
                            while (true) {
                                if (symbolStack.peek().equals("(")) {
                                    symbolStack.pop();
                                    break;
                                } else {
                                    int number2 = numberStack.pop();
                                    int number1 = numberStack.pop();
                                    String symbol = symbolStack.pop();
                                    int result = operation(number1, number2, symbol);
                                    numberStack.push(result);
                                }
                            }
                            continue;
                        }
    
                        // 拿出符号栈顶元素和当前符号对比,如果栈顶符号是 ( 则为0,因为它只有遇到)才有意义
                        String stackTop = symbolStack.peek();
                        int stackTopPriority = priority(stackTop);
                        int priority = priority(current);
                        // 如果当前符号优先级大于栈顶符号优先级,将当前符号添加到栈顶
                        if (priority > stackTopPriority) {
                            symbolStack.push(current);
                        } else {
                            // 如果当前符号优先级小于等于栈顶运算符优先级,则从符号栈顶弹出一个符号
                            // 从数字栈中弹出两个数字做运算 注意:栈顶元素在右
                            // 将结果入数字栈,最后将当前运算符入符号栈
                            int number2 = numberStack.pop();
                            int number1 = numberStack.pop();
                            String symbol = symbolStack.pop();
                            int result = operation(number1, number2, symbol);
                            numberStack.push(result);
                            symbolStack.push(current);
                        }
                    }
                }
            }
            // 最后两个队列可能还有元素,则顺序弹出1个符号和两个数字做运算,并且将结果入数字栈
            while (true) {
                if (symbolStack.isEmpty()) {
                    break;
                } else {
                    int number2 = numberStack.pop();
                    int number1 = numberStack.pop();
                    String symbol = symbolStack.pop();
                    int result = operation(number1, number2, symbol);
                    numberStack.push(result);
                }
            }
            if (numberStack.size() != 1) {
                throw new RuntimeException("运算异常");
            } else {
                return numberStack.pop();
            }
    
        }
    
        // 返回1表示是运算符,返回0表示是数字
        public int symbolOrNumber(String expression) {
            if (expression.equals("+") || expression.equals("-") || expression.equals("*") || expression.equals("/")
                    || expression.equals("(") || expression.equals(")")) {
                return 1;
            } else if (expression.equals("0") || expression.equals("1") || expression.equals("2") || expression.equals("3")
                    || expression.equals("4") || expression.equals("5") || expression.equals("6") || expression.equals("7")
                    || expression.equals("8") || expression.equals("9")) {
                return 0;
            } else {
                throw new RuntimeException("不是数字也不是运算符");
            }
        }
    
        // 返回运算符的等级 * / 高
        public int priority(String symbol) {
            if (symbol.equals("+") || symbol.equals("-")) {
                return 1;
            } else if (symbol.equals("*") || symbol.equals("/")) {
                return 2;
            } else if (symbol.equals("(")) {
                return 0;
            } else {
                throw new RuntimeException("无法识别运算符");
            }
        }
    
        // 获取字符串中第一个连续数字
        public int concatNumber(String str) {
            StringBuilder strNumber = new StringBuilder();
            int index = 0;
            while (true) {
                if (index > str.length() - 1) {
                    break;
                }
                String ch = str.charAt(index) + "";
                if (symbolOrNumber(ch) == 0) {
                    strNumber.append(ch);
                    index++;
                } else {
                    break;
                }
            }
            return Integer.parseInt(strNumber.toString());
        }
    
        // 做运算
        public int operation(int number1, int number2, String symbol) {
            switch (symbol) {
            case "+":
                return number1 + number2;
            case "-":
                return number1 - number2;
            case "*":
                return number1 * number2;
            case "/":
                return number1 / number2;
            default:
                throw new RuntimeException("运算符不正确");
            }
        }
    
    }
    View Code
  • 相关阅读:
    linux网桥浅析
    linux slub分配器浅析
    vs2015 C# WinForm 使用皮肤 美化窗体
    枚举可以直接赋值给int
    LINK : fatal error LNK1000: Internal error during IncrBuildImage
    map映射类
    map
    time
    int to string
    eclipse
  • 原文地址:https://www.cnblogs.com/zumengjie/p/13783007.html
Copyright © 2020-2023  润新知