2020-08-24

中缀表达式和后缀表达式

1. 中缀表达式(栈实现综合计算器)

请输入一个表达式:
计算:722-5+1-5+3-3
思路分析:

  1. 通过一个index值(索引)来遍历我们的表达式;
  2. 如果发现是一个数字,就直接入数栈;
  3. 如果发现扫描到一个符号,就分如下情况;
    3.1 如果当前符号栈为空,就直接入栈;
    3.2 如果符号栈有操作数,就进行比较,如果当前操作符的优先级小于或则和等于栈中的操作符,就需要从数栈种pop出两个数,从符号栈种pop出一个运算符,进行运算,将得到的结果入数栈,然后将当前的操作符入符号栈;如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈;
  4. 当表达式扫描完毕后,就顺序的从数栈和符号栈中pop出相应的数和符号,并运行;
  5. 最后在数栈只有一个数字,就是表达式的结果。
    1
    程序:
import java.util.Stack;

//中缀表达式四则运算,支持多位数(没有括号和负号)
//两个栈实现 四则运算
public class Calculator {
    public static void main(String[] args) {
        String str = "30+4/2-2";
        Stack<String> digital = new Stack<>();
        Stack<String> operator = new Stack<>();
        int index = 0;
        while(index < str.length()){
            String s = str.substring(index,index+1);
            String ss = "";//用于数字拼接
            if(s.charAt(0) >= '0' &&  s.charAt(0) <='9'){
                //如果是数字,此时不能直接入栈;
                //还需要向后再看一位,如果是数字,需要进行拼接
                ss = "";//置为空
                ss += s;
                index++;
                while(index < str.length()) {
                    char tmp = str.substring(index, index + 1).charAt(0);
                    if (tmp < '0' || tmp > '9'){//不为数字
                        break;
                    }else{//为数字
                        ss += tmp;
                    }
                    index++;
                }
                digital.add(ss);
            }else{
                if(operator.isEmpty()){//如果为空,则直接入栈
                    operator.add(s);
                    index++;
                }else{
                    if(getLevel(s) > getLevel(operator.peek())){//如果高于栈顶的运算符号的优先级,则直接入栈
                        operator.add(s);
                        index++;
                    }else{//否则,数栈pop出两个数,符号pop栈顶运算符号,进行运算
                        double[] arrs = new double[2];
                        arrs[0] = Double.valueOf(digital.pop());
                        arrs[1] = Double.valueOf(digital.pop());
                        String op = operator.pop();
                        double res = calculate(arrs, op);//运算
                        digital.add(String.valueOf(res));//结果再入数栈
                        operator.add(s);//最后将当前符号入栈
                        index++;
                    }
                }
            }
        }
        //扫描完毕以后,如果符号栈不为空,执行出栈,运算操作
        while(!operator.isEmpty()){
            double[] arrs = new double[2];
            arrs[0] = Double.valueOf(digital.pop());
            arrs[1] = Double.valueOf(digital.pop());
            String op = operator.pop();
            double res = calculate(arrs, op);
            digital.add(String.valueOf(res));
        }
        System.out.printf("%.3f",Double.valueOf(digital.pop()));
    }
    public static int getLevel(String s){
        int res = -1;
        switch(s){
            case "+":
            case "-":
                res = 1;
                break;
            case "*":
            case "/":
                res = 2;
                break;
        }
        return  res;
    }
    public static double calculate(double[] arrs, String op){
        double res = -1;
        switch(op){
            case "+":
                res = arrs[1] + arrs[0];
                break;
            case "-":
                res = arrs[1] - arrs[0];
                break;
            case "*":
                res = arrs[1] * arrs[0];
                break;
            case "/":
                res = arrs[1] / arrs[0];
                break;
        }
        return res;
    }
}

2. 后缀表达式

中缀表达式转后缀表达式思路:

  1. 初始化两个栈:运算符栈s1和存储中间结果的栈s2
  2. 从左至右扫描中缀表达式;
  3. 遇到操作数时,将其压入s2;
  4. 遇到运算符时,比较其与s1栈顶运算符的优先级
    1)如果s1为空 或 栈顶运算符为 “(” ,则直接将此运算符入栈;
    2)否则,若优先级比栈顶运算符的高,也将运算符压入s1;
    3) 否则,将s1栈顶的运算符弹出,并压入s2中,再次转到4.1与s1中的栈顶运算符相比较;
  5. 遇到括号时:
    1)如果是左括号,则直接压入s1
    2)如果是右括号,则依次弹出s1栈顶的运算符号,并且压入s2,直到遇到左括号为止,此时将这一对括号丢弃;
  6. 重复步骤2至步骤5,直至表达式的最右边
  7. 将s1中剩余的运算符依次弹出并压入s2;
  8. 依次弹出s2中的元素并输出,结果的逆序记为中缀表达式对应的后缀表达式

程序:

public class PolandNotation {
    public static void main(String[] args) {
        //完成将一个中缀表达式转成后缀表达式的功能
        //说明
        //1. 1+((2+3)×4)-5 => 转成  1 2 3 + 4 × + 5 –
        //2. 因为直接对str 进行操作,不方便,因此 先将  "1+((2+3)×4)-5" =》 中缀的表达式对应的List
        //   即 "1+((2+3)×4)-5" => ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]
        //3. 将得到的中缀表达式对应的List => 后缀表达式对应的List
        //   即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]  =》 ArrayList [1,2,3,+,4,*,+,5,–]

        String s="1+((2+3)*4)-5";
        List list1 = toInfixExpressionList(s);
        System.out.println(list1);
        List list2 = parseSuffixExceptionList(list1);
        System.out.println(list2);
    }
    //方法:将 中缀表达式 转成对应的 List
    //s = "1+((2+3)×4)-5";
    public static List<String> toInfixExpressionList(String s){
        //定义一个List存放字符串中的元素
        ArrayList<String> list = new ArrayList<>();
        String str;     //用于数字拼接
        int index = 0;  //遍历字符串的索引
        while(index < s.length()){
            char ch = s.charAt(index);
            //判断试字符还是数字
            if(ch< '0' || ch > '9'){//是字符,直接存入list
                list.add(""+ch);//list中存入字符
                index++;
            }else{      //是数字,需要考虑拼接
                str=""; //先将str 置成"" '0'[48]->'9'[57]
                str+=ch;//字符符串拼接
                index++;//索引下标
                // && 短路运算符 如果第一个不成立,后面的不再进行判断
                // 此处应该先判断索引是否超过字符串的长度,否则不能判断字符范围
                while(index < s.length() && s.charAt(index) >= '0' && s.charAt(index) <= '9'){
                    str += s.charAt(index);
                    index++;
                }
                list.add(str);//list中存入数字
            }
        }
        return list;
    }

    /*
     * 中缀表达式转后缀表达式思路:
     * 1. 初始化两个栈:运算符栈s1和存储中间结果的栈s2
     * 2. 从左至右扫描中缀表达式;
     * 3. 遇到操作数时,将其压入s2;
     * 4. 遇到运算符时,比较其与s1栈顶运算符的优先级
     *   1)如果s1为空 或 栈顶运算符为 “(” ,则直接将此运算符入栈;
     *   2)否则,若优先级比栈顶运算符的高,也将运算符压入s1;
     *   3) 否则,将s1栈顶的运算符弹出,并压入s2中,再次转到4.1与s1中的栈顶运算符相比较;
     * 5. 遇到括号时:
     *   1)如果是左括号,则直接压入s1
     *   2)如果是右括号,则依次弹出s1栈顶的运算符号,并且压入s2,直到遇到左括号为止,此时将这一对括号丢弃;
     * 6. 重复步骤2至步骤5,直至表达式的最右边
     * 7. 将s1中剩余的运算符依次弹出并压入s2;
     * 8. 依次弹出s2中的元素并输出,结果的逆序记为中缀表达式对应的后缀表达式
     *
     * */
    //即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]  =》 ArrayList [1,2,3,+,4,*,+,5,–]
    //方法:将得到的中缀表达式对应的List => 后缀表达式对应的List
    public static List<String> parseSuffixExceptionList(List<String> ls){
        Stack<String> stack = new Stack<>();// 符号栈
        //说明:因为s2 这个栈,在整个转换过程中,没有pop操作,而且后面我们还需要逆序输出
        //因此比较麻烦,这里我们就不用 Stack<String> 直接使用 List<String> s2
        //Stack<String> s2 = new Stack<String>(); // 储存中间结果的栈s2
        List<String> list = new ArrayList<>(); //临时存放数据
        //遍历ls
        for(String s:ls){
            //如果是一个数,加入list
            if(s.matches("\\d+")){
                list.add(s);
            }else if(s.equals("(")){
                //入栈
                stack.push(s);
            }else if(s.equals(")")){
                //如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
                while(!stack.peek().equals("(")){//直至栈顶元素为"("结束
                    list.add(stack.pop());
                }
                stack.pop();//!!! 将 ( 弹出 s1栈, 消除小括号
            }else{//为运算符
                //当item的优先级小于等于s1栈顶运算符, 将s1栈顶的运算符弹出并加入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较
                //问题:我们缺少一个比较优先级高低的方法
                while(stack.size() != 0 && Operation.getValue(stack.peek()) >= Operation.getValue(s)){ //栈顶符号的优先级比s高
                    list.add(stack.pop());
                }
                stack.push(s);
            }

        }
        //栈中剩余的操作符出栈存入list
        while(stack.size() != 0){
            list.add(stack.pop());
        }
        return list;
    }

}

class Operation{
    public static final int ADD=1;
    public static final int SUB=1;
    public static final int MUL=2;
    public static final int DIV=2;

    public static int getValue(String operation){
        int res = 0;
        switch (operation){
            case "+":
                res= ADD;
                break;
            case "-":
                res= SUB;
                break;
            case "*":
                res= MUL;
                break;
            case "/":
                res= DIV;
                break;
            default:
                System.out.println("输入操作符不存在!");
                break;
        }
        return res;
    }

}

后缀表达式运算

  1. 从左至右扫描,将数字入栈;
  2. 遇到运算符号,从栈种pop出两个数字,进行运算,运算结果再入栈;
  3. 数栈的最后一个结果就是最终的运算结果。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值