/*
使用两个栈,一个数字栈,一个符号栈
从左往右遍历表达式字符串
1.遇到数字,直接压入数字栈
2.遇到符号
 (1)遇到左括号,直接入符号栈
 (2)遇到右括号,”符号栈弹栈取栈顶符号b,数字栈弹栈取栈顶数字a1,数字栈弹栈取栈顶数字a2,计算a2 b a1 ,将结果压入数字栈”,重复引号步骤至取栈顶为左括号,将左括号弹出
3.遇到运算符,
 1)若该运算符的优先级大于栈顶元素的优先级,直接入符号栈。
 2)若小于,”符号栈弹栈取栈顶符号b,数字栈弹栈取栈顶数字a1,数字栈弹栈取栈顶数字a2,计算a2 b a1 ,将结果压入数字栈”,重复引号步骤至该运算符的优先级大于符号栈顶元素的优先级,然后将该符号入符号栈
遍历结束后,”符号栈弹栈取栈顶符号b,数字栈弹栈取栈顶数字a1,数字栈弹栈取栈顶数字a2,计算a2 b a1 ,将结果压入数字栈”,重复引号步骤至符号栈无符号(或数字栈只有一个元素),则数字栈的元素为运算结果
*/

七、代码二
环境:

Eclipse Java EE IDE(Version: Oxygen.1a Release (4.7.1a))
jdk1.8.0_131
先写一个最基本的两位数四则运算方法,比较简单,没有写注释:

四则运算java栈 java用栈实现四则运算_优先级

private static double doubleCal(double a1, double a2, char operator) throws Exception {
        switch (operator) {
        case '+':
            return a1 + a2;
        case '-':
            return a1 - a2;
        case '*':
            return a1 * a2;
        case '/':
            return a1 / a2;
        default:
            break;
        }
        throw new Exception("illegal operator!");
    }

四则运算java栈 java用栈实现四则运算_优先级

写一个获得优先级的方法:

四则运算java栈 java用栈实现四则运算_优先级

private static int getPriority(String s) throws Exception {
        if(s==null) return 0;
        switch(s) {
        case "(":return 1;
        case "+":;
        case "-":return 2;
        case "*":;
        case "/":return 3;
        default:break;
        }
        throw new Exception("illegal operator!");
    }

四则运算java栈 java用栈实现四则运算_优先级

解析表达式:

四则运算java栈 java用栈实现四则运算_优先级

public static String getResult(String expr) throws Exception {
        System.out.println("计算"+expr);
        /*数字栈*/
        Stack<Double> number = new Stack<Double>(); 
        /*符号栈*/
        Stack<String> operator = new Stack<String>();
        operator.push(null);// 在栈顶压人一个null,配合它的优先级,目的是减少下面程序的判断

        /* 将expr打散为运算数和运算符 */
        Pattern p = Pattern.compile("(?<!\\d)-?\\d+(\\.\\d+)?|[+\\-*/()]");// 这个正则为匹配表达式中的数字或运算符
        Matcher m = p.matcher(expr);
        while(m.find()) {
            String temp = m.group();
            if(temp.matches("[+\\-*/()]")) {//遇到符号
                if(temp.equals("(")) {//遇到左括号,直接入符号栈
                    operator.push(temp);
                    System.out.println("符号栈更新:"+operator);
                }else if(temp.equals(")")){//遇到右括号,"符号栈弹栈取栈顶符号b,数字栈弹栈取栈顶数字a1,数字栈弹栈取栈顶数字a2,计算a2 b a1 ,将结果压入数字栈",重复引号步骤至取栈顶为左括号,将左括号弹出
                    String b = null;
                    while(!(b = operator.pop()).equals("(")) {
                        System.out.println("符号栈更新:"+operator);
                        double a1 = number.pop();
                        double a2 = number.pop();
                        System.out.println("数字栈更新:"+number);
                        System.out.println("计算"+a2+b+a1);
                        number.push(doubleCal(a2, a1, b.charAt(0)));
                        System.out.println("数字栈更新:"+number);
                    }
                    System.out.println("符号栈更新:"+operator);
                }else {//遇到运算符,满足该运算符的优先级大于栈顶元素的优先级压栈;否则计算后压栈
                    while(getPriority(temp) <= getPriority(operator.peek())) {
                        double a1 = number.pop();
                        double a2 = number.pop();
                        String b = operator.pop();
                        System.out.println("符号栈更新:"+operator);
                        System.out.println("数字栈更新:"+number);
                        System.out.println("计算"+a2+b+a1);
                        number.push(doubleCal(a2, a1, b.charAt(0)));
                        System.out.println("数字栈更新:"+number);
                    }
                    operator.push(temp);
                    System.out.println("符号栈更新:"+operator);
                }
            }else {//遇到数字,直接压入数字栈
                number.push(Double.valueOf(temp));
                System.out.println("数字栈更新:"+number);
            }
        }

        while(operator.peek()!=null) {//遍历结束后,符号栈数字栈依次弹栈计算,并将结果压入数字栈
            double a1 = number.pop();
            double a2 = number.pop();
            String b = operator.pop();
            System.out.println("符号栈更新:"+operator);
            System.out.println("数字栈更新:"+number);
            System.out.println("计算"+a2+b+a1);
            number.push(doubleCal(a2, a1, b.charAt(0)));
            System.out.println("数字栈更新:"+number);
        }
        return number.pop()+"";
    }

四则运算java栈 java用栈实现四则运算_优先级

主方法,以-3.5*(4.5-(4+(-1-1/2)))测试

四则运算java栈 java用栈实现四则运算_优先级

public static void main(String[] args) throws Exception {
        String str = "-3.5*(4.5-(4+(-1-1/2)))";
        System.out.println(getResult(str));
    }

四则运算java栈 java用栈实现四则运算_优先级

四则运算java栈 java用栈实现四则运算_四则运算java栈_09

/*
使用两个栈,一个数字栈,一个符号栈
从左往右遍历表达式字符串
1.遇到数字,直接压入数字栈
2.遇到符号
 (1)遇到左括号,直接入符号栈
 (2)遇到右括号,”符号栈弹栈取栈顶符号b,数字栈弹栈取栈顶数字a1,数字栈弹栈取栈顶数字a2,计算a2 b a1 ,将结果压入数字栈”,重复引号步骤至取栈顶为左括号,将左括号弹出
 (3).遇到运算符,
   1)若该运算符的优先级大于栈顶元素的优先级,直接入符号栈。
   2)若小于,”符号栈弹栈取栈顶符号b,数字栈弹栈取栈顶数字a1,数字栈弹栈取栈顶数字a2,计算a2 b a1 ,将结果压入数字栈”,重复引号步骤至该运算符的优先级大于符号栈顶元素的优先级,然后将该符号入符号栈
3.遍历结束后,”符号栈弹栈取栈顶符号b,数字栈弹栈取栈顶数字a1,数字栈弹栈取栈顶数字a2,计算a2 b a1 ,将结果压入数字栈”,重复引号步骤至符号栈无符号(或数字栈只有一个元素),则数字栈的元素为运算结果
*/

//难点:区分负号和减号,数字-数字,为减号;右括号-数字,为减号,即-数字前面不是数字或者右括号为负数。

解决:正则表达式的正向预查和反向预查


import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in); 
        while(sc.hasNext()) {
            String expr = sc.nextLine();
            System.out.println(getResult(expr));
            
        }
        
    } 
    public static String getResult(String expr) {
        //数字栈
        Stack<Integer> number = new Stack<>();
        //符号栈
        Stack<String> operator = new Stack<>();
        operator.push(null);//压入null,用于比较优先级
        
        /* 将expr打散为运算数和运算符 */
        //难点:区分负号和减号,数字-数字,为减号;右括号-数字,为减号,即-数字前面不是数字或者右括号为负数
        Pattern p = Pattern.compile("(?<!\\d+|\\))-?\\d+|[+\\-*/()]");
        Matcher m = p.matcher(expr);
        while(m.find()) {
            String temp = m.group();
            if(temp.matches("[+\\-*/()]")) {
                //遇到左括号,入栈
                if(temp.equals("(")) {
                    operator.push(temp);
                //遇到右括号,取符号栈栈顶符号b,数字栈栈顶a1,数字栈栈顶a2,计算a2 b a1 ,结果存入数字栈,直到遇到左括号,
                }else if(temp.equals(")")) {
                    String b = null;
                    while(!(b=operator.pop()).equals("(")) {
                        int a1 = number.pop();
                        int a2 = number.pop();
                        number.push(cal(a2,a1,b.charAt(0)));
                    }
                //遇到运算符,满足该运算符的优先级大于栈顶元素的优先级压栈;否则计算后压栈
                }else {
                    while(getPriority(temp)<= getPriority(operator.peek())) {
                        String b =operator.pop();
                        int a1 = number.pop();
                        int a2 = number.pop();
                        
                        number.push(cal(a2,a1,b.charAt(0)));
                    }
                    operator.push(temp);
                }
            }else {//遇到数字,入栈
                number.push(Integer.valueOf(temp));
                
            }
            
        }
        
        //遍历结束后,符号栈数字栈依次弹栈计算,并将结果压入数字栈
        while(operator.peek()!=null ) {
            
            int a1 = number.pop();
            int a2 = number.pop();
            String b = operator.pop();

            number.push(cal(a2, a1, b.charAt(0)));
        }
        return number.pop()+"";
    }
    //两项的四则运算
    public static Integer cal(int a1, int a2, char b) {
        switch(b) {
            case '+':
                return a1+a2;
            case '-':
                return a1-a2;
            case '*':
                return a1*a2;
            case '/':
                return a1/a2;
            default:
                break;
        }
        return 0;
    }
    //获取优先级
    public static int getPriority(String s) {
        if(s==null) return 0;
        switch(s) {
            case "(":
                return 1;
            case "+":
            case "-":
                return 2;
            case "*":
            case "/":
                return 3;
            default:
                break;
        }
        return 0;
    }
}