前缀、中缀、后缀(逆波兰)表达式以及逆波兰表达式实现简单计算器

概念及计算思路

这里主要研究的是后缀表达式即逆波兰表达式

前缀表达式

前缀表达式及波兰表达式
1.前缀表达式又称波兰表达式,前缀表达式的运算符位于操作数之前
2.举例说明:(3+4)*5-6 对应的前缀表达式就是- * + 3456
前缀表达式的计算机求值
从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对他们做相应的计算,并将结果入栈,重复上述过程直到表达式的最左端,最后运算得出的值即为表达式的结果
例如:(3+4)5-6 对应的前缀表达式就是- * + 3456,针对前缀表达式求值的步骤如下:
1.从右到左扫描,将6、5、4、3压入堆栈
2.遇到运算符+,弹出3、4计算3+4的值,得到7在入栈
3.扫描到
运算符,因此弹出7、5,运算得到35,入栈
4.最后时运算符-,计算出35-6的值,及29,得出最终结果

中缀表达式

1.中缀表达式就是最常见的运算表达式,如(3+4)*5-6
2.中缀表达式的求值是我们最熟悉的,但是对计算计来说却不好操作,因此在计算结果时,往往会将中缀表达式转成其他表达式来处理,一般是转化为后缀表达式
对于这个大家应该熟悉的吧

后缀表达式

后缀表达式(逆波兰表达式)
1.后缀表达式又称为逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后
2.(3+4)*5-6,同样用这个举例,对应的后缀表达式是 3 4 + 5 * 6 -
后缀表达式的计算机求值
从左到右扫描表达式,遇到数字压入数栈,遇到运算符时,弹出栈顶的两个数,用运算符进行计算,并将结果入栈,重复上述过程直到表达式的最右端,最后运算得出的值即为表达式的结果。

逆波兰计算器

1.先简单完成一个逆波兰表达式,使用栈,计算其结果
2.支持小括号和多位数整数,对计算器进行简化,只支持对整数的计算
3.思路分析:即上述的后缀表达式的计算求值的思路
4.但我们不能要求别人输入的是转换好的逆波兰表达式,因此还需要将中缀表达式转化为后缀表达式。

中缀表达式转换为后缀表达式

后缀表达式的确适合计算机的计算,但人还是习惯于中缀表达式,因此我们还是需要将中缀表达式啊转换为后缀表达式的
具体的步骤如下
1.初始化两个栈,运算符栈s1和存储中间结果的栈s2
2.从左至右的扫描中缀表达式
3.遇到操作数时将其压入s2
4.遇到运算符时,比较其s1栈顶运算符的优先级
1.如果s1为空,或者栈顶符号为为(,则将此运算符直接入栈
2.否则,若优先级比栈顶元素的优先级高,也将其压入s1
3.否则,将s1栈顶的运算符弹出并压入s2中,再次与运算符栈的新的栈顶元素进行比较。
5.遇到括号时
1.如果是( 直接压入s1
2.如果是 ) 依次弹出s1中的运算符,然后压入s2,直到遇到 ( 为止然后丢弃这对括号
6.重复以上的2-5的操作直到到中缀表达式的最右边结束
7.将s1中的运算符依次弹出,并压入s2
8.依次弹出s2中的元素,结果的逆序就是中缀转后缀之后的 后缀表达式
如下图例子的思路
在这里插入图片描述

注:真正的代码实现的时候,中间结果并不需要一定要去存入栈,他不需要去弹栈,全程只是添加进去,若是用栈去存储,最后还涉及到一个栈的逆序的问题,实现的时候用list会更方便些
废话不多说代码放上边,主函数那里自己测试的有点乱奥
这里就不用自己模拟的栈了

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class polanNotation {
    public static void main(String[] args) {
        //要完成将中缀表达式转为后缀表达式
        //转化之前是字符串,要对字符串进行扫描
        //直接对字符串进行扫描的话需要辅助指针index比较麻烦,因此这里先将字符串转化为一个中缀的list
        //将中缀表达式转化为的list转化为后缀表达式的list
        String exp1="(3+9)*5-60";
        List<String> strings1 = parseSuffixExp(toInfixExp(exp1));
        System.out.println(strings1);
        System.out.println(cal((ArrayList<String>) strings1));
        System.out.println("*************");


        //先列出一个中缀表达式(3+4)*5-6
        //将该运算表达式转换为后缀表达式为34+5*6-
        //为了运算的简单我们直接在转换后的每个个体中间加上空格
        String suffixExp="3 9 + 5 * 60 -";
        //思路分析
        //先将3 4 + 5 * 6 -放入一个arraylist中
        //再将arraylist传递给一个方法,配合栈完成计算
        List<String> list = getListString(suffixExp);
        System.out.println(list);
        int cal = cal((ArrayList<String>) list);
        System.out.println(cal);
        System.out.println("***********************");
        String exp="(2+3)*4";
        List<String> strings = toInfixExp(exp);
        System.out.println(strings);
    }
    public static List<String> getListString(String suffixExp){
        String[] s = suffixExp.split(" ");
        List<String> strings = new ArrayList<String>();
        for (String s1 : s) {
            strings.add(s1);
        }
        return strings;
    }
    public static  int cal(ArrayList<String> list){
        //创建栈只需要一个栈即可。
        Stack<String> strings = new Stack<String>();
        for (String s : list) {
            if(s.matches("\\d+")){
                strings.push(s);
            }else{
                int num1=Integer.parseInt(strings.pop());
                int num2=Integer.parseInt(strings.pop());
                int res=0;
                if(s.equals("+")){
                    res=num1+num2;
                }else if(s.equals("*")){
                    res=num1*num2;
                }else if(s.equals("+")){
                    res=num1+num2;
                }else if(s.equals("-")){
                    res=num2-num1;
                }else{
                    throw new RuntimeException("符号有误");
                }
                strings.push(""+res);
            }
        }
        //最后留在栈中的是运算结果
        return Integer.parseInt(strings.pop());
    }
    //将中缀表达式转成对应的list
    public static  List<String>  toInfixExp(String exp){
        ArrayList<String> strings = new ArrayList<String>();
        int i=0;//这是一个指针,用来遍历中缀表达式
        //用来做多位数的拼接工作
        String str;
        char ch;
        do{
            //如果是一个非数字就加入strings
           if((ch=exp.charAt(i))<48 || (ch=exp.charAt(i))>57 ){
               strings.add(""+ch);
               i++;
           }else{//如果是数字则要考虑多位数字的拼接问题
               str="";
               while(i<exp.length() && (ch=exp.charAt(i))>=48 && (ch=exp.charAt(i))<=57 ){
                   str+=ch;
                   i++;
               }
               strings.add(str);
           }
        }while(i<exp.length());
        return strings;
    }
    //中缀表达式的list转化为后缀表达式的list
    public  static  List<String>  parseSuffixExp(List<String> list){
        //先定义两个栈
        Stack<String> s1=new Stack<String>();
        //按照我们的思路分析这里应该用一个中间数字的栈
        //而且这个栈从头到尾都没有说进行出栈的操作
        //最后还要对遍历的栈进行逆序,这里我们可以不用这个栈,直接使用list来替代这个栈
        List<String> s2 = new ArrayList<String>();//存中间数
        for (String s : list) {
            if(s.matches("\\d+")){
                s2.add(s);
            }else if(s.equals("(")){
                s1.push(s);
            }else if(s.equals(")")){//如果是 ) 依次弹出s1中的运算符,然后压入s2,直到遇到 ( 为止然后丢弃这对括号
                while(!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                s1.pop();//消除小括号

            }else{//若s是运算符号,优先级小于等于栈顶的优先级,s1弹栈并加入到s2中
                while(!s1.isEmpty() &&  Operation.getValue(s1.peek())>Operation.getValue(s)){//需要一个比较优先级高低的方法
                    s2.add(s1.pop());
                }
                s1.push(s);

            }
        }
        while (!s1.isEmpty()){
            s2.add(s1.pop());
        }
        return s2;//数序遍历就是该表达式的逆波兰表达式;
    }
}
//用来比较优先级高低
class Operation{
    private static int ADD=1;
    private static int SUB=1;
    private static int MUl=2;
    private static int Div=2;
    public static int getValue(String operation){
           int res=0;
           switch(operation){
               case "*":
                   res= MUl;
                   break;
               case "/":
                   res=Div;
                   break;
               case "+":
                   res=ADD;
                   break;
               case "-":
                   res=SUB;
                   break;
               default:
//                   System.out.println("this oper is not exist");
                   break;
           }
           return res;
    }
}

还是喜欢晚上的,哈哈哈哈哈嗝
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Quare_feifei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值