数据结构与算法分析----栈+中缀、后缀表达式(逆波兰表达式)+中后缀对应计算器的实现

概述

百度百科:栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
简单来说:就是一种先入后出的存储数据的容器。
想象一下乌鸦喝水,瓶子就是栈,乌鸦投入的石子就是元素,投入的第一个石子直接到栈底,然后最后一个石子到栈顶,如果乌鸦要把石子取出来,也只能从栈顶一个一个取石子,即按照后入先出的顺序取。
在这里插入图片描述
找图的时候,这个图片笑死我了,加上!

用数组作为底层实现一个栈

  1. 栈中应有的属性
    在这里插入图片描述
    用一个属性来记录栈顶,方便判断栈是否为空,是否已满。初始化为-1表示栈为空
    maxSize用来表示栈的最大容量,可用此值创建底层的数组
    创建一个数组作为栈的底层
  2. 构造方法
    在这里插入图片描述
    构造方法中接收一个参数,此参数表示栈的最大容量,并用来创建栈底层的数组
  3. 判断栈满和栈空
    在这里插入图片描述
    top从-1开始,maxSize从0开始所以这里是maxSize-1
  4. 入栈
    在这里插入图片描述
    先判断是否已满,满则结束方法,不满则将top加一位,然后用top作数组的索引,向数组对应的地方存入数据
  5. 出栈
    在这里插入图片描述
    出栈不需要对数组中的元素进行删除一类的操作,只需要将此事top的值作为索引,返回此索引下数组的值,并将top减一位
  6. 遍历显示栈
    在这里插入图片描述
    先判断,通过后直接按照top——0的顺序,遍历数组即可
  7. 显示栈顶元素
    在这里插入图片描述
    此操作仅显示一下栈顶的数据,并不出栈

全部代码

import java.util.Scanner;

public class ArrayStackDemo {
    
    
    public static void main(String[] args) {
    
    
        Scanner sc=new Scanner(System.in);
        String choice;
        ArrayStack stack=null;
        while (true){
    
    
            System.out.println("创建栈,1。退出,0。");
            boolean flag=false;
            choice=sc.next();
            if (choice.equals("1")){
    
    
                String Size;
                int ISize;
                while (true){
    
    
                    System.out.println("输入大小");
                    Size=sc.next();
                    try {
    
    
                        ISize=Integer.parseInt(Size);

                        break;
                    }catch (Exception e){
    
    
                        System.out.println("输入错误");
                    }
                }
                stack=new ArrayStack(ISize);
                flag=true;
            }else if(choice.equals("0")){
    
    
                break;
            }
            if (flag){
    
    
                while (true) {
    
    
                    System.out.println("入栈,1。出栈,2。全部显示,3。返回,0");
                    String choice2;
                    choice2=sc.next();
                    if (choice2.equals("1")) {
    
    
                        String Value;
                        int IValue;
                        while (true) {
    
    
                            System.out.println("输入数值");
                            Value = sc.next();
                            try {
    
    
                                IValue = Integer.parseInt(Value);
                                break;
                            } catch (Exception e) {
    
    
                                System.out.println("输入错误");
                            }
                        }
                        stack.push(IValue);
                    }else if (choice2.equals("2")){
    
    
                        try {
    
    
                            System.out.println(stack.pop());
                        }catch (Exception e){
    
    
                            System.out.println(e.getMessage());
                        }

                    }else if (choice2.equals("3")){
    
    
                        stack.show();
                    }else if (choice2.equals("0")){
    
    
                        break;
                    }
                }
            }
        }
    }
}
class ArrayStack{
    
    
    private int top=-1; //栈顶,初始化为-1
    private int maxSize;  //栈最大容量
    private int[] Stack;  //栈底层用数组实现

//    构造方法,对栈初始化
    public ArrayStack(int maxSize) {
    
    
        this.maxSize = maxSize;
        this.Stack = new int[this.maxSize];
    }

//    判断是否栈满
    public Boolean isFull(){
    
    
        return top==maxSize-1;
    }

//    判断栈空
    public Boolean isEmpty(){
    
    
        return top==-1;
    }

//    入栈
    public void push(int Value){
    
    
//        先判断是否满
        if (isFull()){
    
    
            System.out.println("栈满");
            return;
        }
        Stack[++top]=Value;
    }

//    出栈
    public int pop(){
    
    
//        先判断栈是否为空
        if (isEmpty()){
    
    
//            若为空,则抛出异常
            throw new RuntimeException("栈空,无数据");
        }
        return Stack[top--];
    }

//    遍历显示栈
    public void show(){
    
    
        if (isEmpty()){
    
    
            System.out.println("栈空");
            return;
        }
        for (int i = top; i >=0; i--) {
    
    
            System.out.println("Stack["+i+"]-------"+Stack[i]);
        }
    }

//    显示栈顶的数据
    public int peek(){
    
    
        //        先判断栈是否为空
        if (isEmpty()){
    
    
//            若为空,则抛出异常
            throw new RuntimeException("栈空,无数据");
        }
        return Stack[top];
    }
}

中缀和后缀表达式

中缀表达式

百度百科:
(或中缀记法)是一个通用的算术或逻辑公式表示方法,操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。
与前缀表达式(例:+ 3 4)或后缀表达式(例:3 4 +)相比,中缀表达式不容易被计算机解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。
与前缀或后缀记法不同的是,中缀记法中括号是必需的。计算过程中必须用括号将操作符和对应的操作数括起来,用于指示运算的次序。
简单来说,中缀表达式是对数字计算的一种表达方式,如1+(2-1)*3+4。就是我们小学学习的数学计算式。

后缀表达式(逆波兰表达式)

后缀表达式又被称为逆波兰表达式,前缀表达式被称为波兰表达式
百度百科
一个表达式E的后缀形式可以如下定义:
(1)如果E是一个变量或常量,则E的后缀式是E本身。
(2)如果E是E1 op E2形式的表达式,这里op是任何二元操作符,则E的后缀式为E1’E2’ op,这里E1’和E2’分别为E1和E2的后缀式。
(3)如果E是(E1)形式的表达式,则E1的后缀式就是E的后缀式。
如:我们平时写a+b,这是中缀表达式,写成后缀表达式就是:ab+
简单来说,后缀表达式也是对数字计算的一种表达方式,
如一个稍微复杂一点的:1, 2, 3, +, *, 6, -, 6, 1, 2, +, /, -
他是1*(2+3)-6-(6/(1+2))这个中缀表达式转为后缀表达式后的样子
一般他的运算符都是在数字的靠后面部分,而且他不能有括号

中缀转后缀的思路

百度百科
将一个普通的中缀表达式转换为逆波兰表达式的一般算法是:
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为存放结果(逆波兰式)的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。可指定其他字符,不一定非#不可。从中缀式的左端开始取字符,逐序进行如下步骤:
(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈。
(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符(不包括括号运算符)优先级高于S1栈栈顶运算符(包括左括号)优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符(包括左括号)低于(不包括等于)该运算符优先级时停止弹出运算符,最后将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈顶。
(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符。
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
完成以上步骤,S2栈便为逆波兰式输出结果。不过S2应做一下逆序处理。便可以按照逆波兰式的计算方法计算了!
或者
中缀转后缀的思路:
创建两个栈(这里为了方便,用的是一个栈和一个集合)S1,S2。
遍历中缀表达式集合,对其中的元素进行如下判断和操作

  1. 若元素是数字,则直接入S2。
  2. 若为左括号"(",则直接入S1栈。
  3. 若为运算符,则判断S1是否为空,若为空则直接如S1,若不为空,则将此元素与S1栈顶的运算符作比较,若此运算符级别高,则直接如S1,若此元素级别低,则将S1栈顶运算符出栈,并,入S2
    然后再将此元素与栈顶运算符作比较,一直循环,直到S1变为空,或栈顶优先级低于此元素,或遇到左括号"("停止,停止后将此元素入栈
  4. 若为右括号,则持续将S1栈顶元素作出栈,并,入S2,直到遇到右括号")“停止,此时再对S1栈作一次出栈操作,是为了将其中的左括号”("删去,此时,右括号也不需要,直接忽略即可

遍历结束后,将S1栈边出栈边入S2,最后得到的S2,按照从栈底向栈顶顺序来,此即为后缀表达式的栈。所以此处我用集合替代S2,到最后,集合S2从索引0到尾部即为一个后缀表达式集合

实现两种计算器

这里根据中缀表达式实现两种计算器。一种是直接边分析中缀表达式边实现计算,另一种是先对中缀表达式进行分析,将其转换为后缀表达式后再进行计算
两者优劣
明显,中缀转后缀,再计算结果更符合计算机的逻辑原理,且在计算过程中更不容易出错

中缀表达式计算器

这里的这个实现未实现加入括号的情况,懒得再搞了,头痛

中缀表达式计算器思路

  1. 将中缀表达式的字符串转为字符数组
  2. 创建两个栈,一个作为符号栈,一个作为数字栈
  3. 然后遍历字符数组,若遇到数字,则直接入数字栈
    若遇运算符,则进行循环操作,操作如下:
    若判断符号栈是否为空,为空则直接入符号栈,跳出循环
    若不为空,则判断当前字符和栈顶字符的优先级,若栈顶低,则直接入栈,跳出循环
    若栈顶的级别高或和当前运算符优先级相等,则把栈顶的符号出栈,再从数字栈中出栈两个数字num1,num2,然后将其进行运算,然后将得到的结果如数字栈,然后再将当前字符和栈顶字符进行对比,进行循环
    循环结束条件:符号栈为空,或栈顶级别低于当前运算符
  4. 上述操作结束后,对符号栈作出栈操作,每次符号栈出一个,数字栈出俩进行运算,将结果如数字栈,持续操作,到最后留在数字栈中的那个数字即为最终结果

实现

这里使用自己手写的以数组作为底层的栈

class ArrayStack2{
    
    
    private int top=-1; //栈顶,初始化为-1
    private int maxSize;  //栈最大容量
    private int[] Stack;  //栈底层用数组实现

    //    构造方法,对栈初始化
    public ArrayStack2(int maxSize) {
    
    
        this.maxSize = maxSize;
        this.Stack = new int[this.maxSize];
    }

    //    判断是否栈满
    public Boolean isFull(){
    
    
        return top==maxSize-1;
    }

    //    判断栈空
    public Boolean isEmpty(){
    
    
        return top==-1;
    }

    //    入栈
    public void push(int Value){
    
    
//        先判断是否满
        if (isFull()){
    
    
            System.out.println("栈满");
            return;
        }
        Stack[++top]=Value;
    }

    //    出栈
    public int pop(){
    
    
//        先判断栈是否为空
        if (isEmpty()){
    
    
//            若为空,则抛出异常
            throw new RuntimeException("栈空,无数据");
        }
        return Stack[top--];
    }

    //    遍历显示栈
    public void show(){
    
    
        if (isEmpty()){
    
    
            System.out.println("栈空");
            return;
        }
        for (int i = top; i >=0; i--) {
    
    
            System.out.println("Stack["+i+"]-------"+Stack[i]);
        }
    }

//    返回栈顶的值,但并不是出栈
    public int peek(){
    
      //这里不用抛出异常,后面用到这个方法是栈里一定有数据的情况下
        return Stack[top];
    }
}

这里在实现计算器的类中需要三个工具方法
在这里插入图片描述因为char和int是相通的,所以这里的一些本该定义为char类型的形参我用int类型替代

下面直接来实现

public int calculate(String str){
    
      //接受一个中缀表达式的字符串
        ArrayStack2 numStack=new ArrayStack2(50);
        ArrayStack2 operStack=new ArrayStack2(50);
        int index,num1,num2,oper,res;
        //index作为字符数组索引,num1和num2用来接收从栈中取出的数字,oper用来接收从栈中取出的运算符,res接收num1、num2、oper运算出的结果
        int sum;  //在分析中缀表达式的时候,数字可能是多位数,sum用来整合数字
        char[] chars=str.toCharArray();  //直接通过字符串的toCharArray()方法把字符串转为字符数组

        for (index = 0; index < chars.length; index++) {
    
      //遍历循环此数组
//            当字符为运算符
            if (isOper(chars[index])){
    
    
                while (true) {
    
    
                    //                先判断符号栈是否为空
                    if (!operStack.isEmpty()) {
    
    
                        //                    不为空则先判断当前字符和符号栈顶字符的优先级
                        if (priority(chars[index]) <= priority(operStack.peek())) {
    
    
                            //                      若栈顶的级别高或和当前运算符优先级相等,则把栈顶的符号出栈
                            oper = operStack.pop();
                            //                      再从数字栈中出栈两个数字num1,num2
                            num1 = numStack.pop();
                            num2 = numStack.pop();
                            //                        然后将其进行运算
                            res = cal(num1, num2, oper);
                            //                        然后将得到的结果如数字栈
                            numStack.push(res);
                        } else {
    
    
                            //                        栈顶级别低,则直接当前符号入栈
                            operStack.push(chars[index]);
                            break;
                        }
                    }else {
    
    
                        //                    为空则直接入栈
                        operStack.push(chars[index]);
                        break;
                    }
                }
            }else {
    
    
                sum=chars[index]-48;
//                当字符为数字,这里整合多位数
                while (index+1<chars.length&&!isOper(chars[index+1])){
    
    
                    sum=sum*10+(chars[index+1]-48);
                    index++;
                }
                numStack.push(sum);
            }
        }
        while (!operStack.isEmpty()){
    
    
//            对残留在栈中的数字字符依次运算
            oper=operStack.pop();
            num1=numStack.pop();
            num2=numStack.pop();
            res=cal(num1,num2,oper);
            numStack.push(res);
        }
        return numStack.pop();
    }

全部代码

public class Calculator {
    
    
    public static void main(String[] args) {
    
    
        CalculatorDemo calculator=new CalculatorDemo();
        System.out.println(calculator.calculate("1-2*2+3"));
    }
}
class ArrayStack2{
    
    
    private int top=-1; //栈顶,初始化为-1
    private int maxSize;  //栈最大容量
    private int[] Stack;  //栈底层用数组实现

    //    构造方法,对栈初始化
    public ArrayStack2(int maxSize) {
    
    
        this.maxSize = maxSize;
        this.Stack = new int[this.maxSize];
    }

    //    判断是否栈满
    public Boolean isFull(){
    
    
        return top==maxSize-1;
    }

    //    判断栈空
    public Boolean isEmpty(){
    
    
        return top==-1;
    }

    //    入栈
    public void push(int Value){
    
    
//        先判断是否满
        if (isFull()){
    
    
            System.out.println("栈满");
            return;
        }
        Stack[++top]=Value;
    }

    //    出栈
    public int pop(){
    
    
//        先判断栈是否为空
        if (isEmpty()){
    
    
//            若为空,则抛出异常
            throw new RuntimeException("栈空,无数据");
        }
        return Stack[top--];
    }

    //    遍历显示栈
    public void show(){
    
    
        if (isEmpty()){
    
    
            System.out.println("栈空");
            return;
        }
        for (int i = top; i >=0; i--) {
    
    
            System.out.println("Stack["+i+"]-------"+Stack[i]);
        }
    }

//    返回栈顶的值,但并不是出栈
    public int peek(){
    
      //这里不用抛出异常,后面用到这个方法是栈里一定有数据的情况下
        return Stack[top];
    }
}
class CalculatorDemo{
    
    
    private int priority(int oper){
    
    //获得运算符优先级
        if (oper=='/'||oper=='*'){
    
    
            return 1;
        }else if (oper=='+'||oper=='-'){
    
    
            return 0;
        }else {
    
    
            return -1;
        }
    }
    private boolean isOper(int val){
    
    
        return val=='*'||val=='/'||val=='-'||val=='+';
    }//判断传入的字符是否是运算符
    private int cal(int num1,int num2,int pre){
    
      //运算
        int res=0;
        switch (pre){
    
    
            case '+':
                res = num1+num2;
                break;
            case '-':
                res = num2-num1;
                break;
            case '*':
                res = num1*num2;
                break;
            case '/':
                res = num2/num1;
                break;
        }
        return res;
    }
    public int calculate(String str){
    
      //接受一个中缀表达式的字符串
        ArrayStack2 numStack=new ArrayStack2(50);
        ArrayStack2 operStack=new ArrayStack2(50);
        int index,num1,num2,oper,res;
        //index作为字符数组索引,num1和num2用来接收从栈中取出的数字,oper用来接收从栈中取出的运算符,res接收num1、num2、oper运算出的结果
        int sum;  //在分析中缀表达式的时候,数字可能是多位数,sum用来整合数字
        char[] chars=str.toCharArray();  //直接通过字符串的toCharArray()方法把字符串转为字符数组

        for (index = 0; index < chars.length; index++) {
    
      //遍历循环此数组
//            当字符为运算符
            if (isOper(chars[index])){
    
    
                while (true) {
    
    
                    //                先判断符号栈是否为空
                    if (!operStack.isEmpty()) {
    
    
                        //                    不为空则先判断当前字符和符号栈顶字符的优先级
                        if (priority(chars[index]) <= priority(operStack.peek())) {
    
    
                            //                      若栈顶的级别高或和当前运算符优先级相等,则把栈顶的符号出栈
                            oper = operStack.pop();
                            //                      再从数字栈中出栈两个数字num1,num2
                            num1 = numStack.pop();
                            num2 = numStack.pop();
                            //                        然后将其进行运算
                            res = cal(num1, num2, oper);
                            //                        然后将得到的结果如数字栈
                            numStack.push(res);
                        } else {
    
    
                            //                        栈顶级别低,则直接当前符号入栈
                            operStack.push(chars[index]);
                            break;
                        }
                    }else {
    
    
                        //                    为空则直接入栈
                        operStack.push(chars[index]);
                        break;
                    }
                }
            }else {
    
    
                sum=chars[index]-48;
//                当字符为数字,这里整合多位数
                while (index+1<chars.length&&!isOper(chars[index+1])){
    
    
                    sum=sum*10+(chars[index+1]-48);
                    index++;
                }
                numStack.push(sum);
            }
        }
        while (!operStack.isEmpty()){
    
    
//            对残留在栈中的数字字符依次运算
            oper=operStack.pop();
            num1=numStack.pop();
            num2=numStack.pop();
            res=cal(num1,num2,oper);
            numStack.push(res);
        }
        return numStack.pop();
    }
}

中缀转后缀计算器

这个更严谨一些,且更准确。更符合计算机来阅读
整体思路就是先把中缀表达式转为后缀表达式,再对后缀表达式进行求值
对后缀表达式求值非常简单,这里面的关键在于如何把中缀表达式转为后缀表达式

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

和百度百科讲的八九不离十,上面有
在这里插入图片描述
这里再说一下这个程序的思路
中缀转后缀的思路:
创建两个栈(这里为了方便,用的是一个栈和一个集合)S1,S2。
遍历中缀表达式集合,对其中的元素进行如下判断和操作

  1. 若元素是数字,则直接入S2。
  2. 若为左括号"(",则直接入S1栈。
  3. 若为运算符,则判断S1是否为空,若为空则直接如S1,若不为空,则将此元素与S1栈顶的运算符作比较,若此运算符级别高,则直接如S1,若此元素级别低,则将S1栈顶运算符出栈,并,入S2
    然后再将此元素与栈顶运算符作比较,一直循环,直到S1变为空,或栈顶优先级低于此元素,或遇到左括号"("停止,停止后将此元素入栈
  4. 若为右括号,则持续将S1栈顶元素作出栈,并,入S2,直到遇到右括号")“停止,此时再对S1栈作一次出栈操作,是为了将其中的左括号”("删去,此时,右括号也不需要,直接忽略即可

遍历结束后,将S1栈边出栈边入S2,最后得到的S2,如果S2是栈,按照从栈底向栈顶顺序来,此即为后缀表达式的栈。所以此处我用集合替代S2,到最后,集合S2从索引0到尾部即为一个后缀表达式集合

实现

这里为了方便,不再重复自己编写栈,直接用Java中的栈(Stack类)

  1. 先两个工具方法,一个判断运算符优先级,一个运算,这里不需要判断是否是优先级的方法(可以搞也可以不搞)
    在这里插入图片描述
    在这里插入图片描述
  2. 处理接收到的中缀表达式,将其中的元素转换为字符串,存储到集合中
    在这里插入图片描述
  3. 中缀转后缀
    在这里插入图片描述
    最后得到的S2即为后缀表达式的集合
  4. 计算后缀表达式
    先接收中缀表达式的字符串,在调用方法,转换为后缀表达式,再遍历集合,进行运算
    在这里插入图片描述
    最后将结果进行类型的转换,然后返回即可

全部代码

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

public class CalculatorSecondTest {
    
    
    public static void main(String[] args) {
    
    
        String str="1*(2+3)-6-(6/(1+2))";  //定义一个中缀表达式
        CalculatorSecond Calculator=new CalculatorSecond();
        try {
    
    
            System.out.println(str+"="+Calculator.GetResult(str));  //调用方法
        }catch (Exception e){
    
    
            System.out.println(e);
        }
    }
}
class CalculatorSecond{
    
    
//    第一步,中缀表达式字符串转集合
    public List<String> ReturnList(String str){
    
    
//        创建集合,用来存储中缀表达式中的元素
        List<String> StrList=new ArrayList<String>();
        int i=0; //索引,用来遍历中缀字符串

        char c;//c用来暂存字符串中的单个字符
        String string; //string用来暂存中缀表达式中的元素

        do {
    
    
//            先判断单个字符是否是运算符,是的话直接存入集合中
            if ((c=str.charAt(i))<48||(c=str.charAt(i))>57){
    
    
                StrList.add(c+"");
                i++;
            }else {
    
    
//                若不是,则说明是数字,下面判断数字后面是否紧跟有数字,若有,则说明是多位数
                string="";  //初始化string
                while (i<str.length()&&((c=str.charAt(i))>=48&&(c=str.charAt(i))<=57)){
    
    
                    string=string+str.charAt(i);  //若为多位数,则进行字符串拼接,将多个数字拼在一起成为多位数,并用string接收
                    i++;
                }
                StrList.add(string); //将string存入集合
            }
        }while (i<str.length());  //循环结束的条件是索引小于字符串的长
        return StrList;  //返回得到的集合
    }
//    中缀转后缀
    public List<String> ReturnRPN(List<String> Str){
    
      //这里接收一个由中缀表达式中的元素构成的集合
        Stack<String> S1=new Stack<String>();       //创建第一个栈S1
        List<String> S2=new ArrayList<String>();   //因为最后得到的栈需要进行逆序,这里为了方便,直接用集合代替S2
        for (String str: Str){
    
    
            if (str.matches("\\d+")){
    
      //1. 用正则来判断是否是数字,若元素是数字,则直接入S2。
                S2.add(str);
            }else if (str.equals("(")){
    
        //   2. 若为左括号"(",则直接入S1栈。
                S1.push("(");
            }else if (str.equals(")")){
    
      //     3. 若为右括号,则持续将S1栈顶元素作出栈,并,入S2,直到遇到右括号")"停止
                while (!S1.peek().equals("(")){
    
    
                    S2.add(S1.pop());
                }
                S1.pop();//此时再对S1栈作一次出栈操作,是为了将其中的左括号"("删去,此时,右括号也不需要,直接忽略即可
            }else{
    
    
//    4. 若为运算符,则判断S1是否为空,若为空则直接如S1,若不为空,则将此元素与S1栈顶的运算符作比较,若此运算符级别高,则直接如S1,若此元素级别低,则将S1栈顶运算符出栈,并,入S2
//        然后再将此元素与栈顶运算符作比较,一直循环,直到S1变为空,或栈顶优先级低于此元素,或遇到左括号"("停止,停止后将此元素入栈
                while (S1.size()!=0&&!S1.peek().equals("(")&&compare(S1.peek())>=compare(str)){
    
    
//                为防止出现异常,先判断S1,是否为空,再判断S1栈顶是否是左括号,再判断优先级     compare是自己编写的一个根据运算符返回对应级别的方法
                    S2.add(S1.pop());
                }
                S1.push(str);  //循环结束后,将当前运算符入栈
            }
        }
        while (S1.size()!=0){
    
    
//        遍历结束后,将S1栈边出栈边入S2,最后得到的S2,按照从栈底向栈顶顺序来,此即为后缀表达式的栈。所以此处我用集合替代S2,到最后,集合S2从索引0到尾部即为一个后缀表达式集合
//            最后循环遍历S1,将S1中元素入S2
            S2.add(S1.pop());
        }
        System.out.println("S2----"+S2);
        return S2;
    }
//    判断运算符优先级
    public int compare(String string){
    
    
        if (string.equals("+")||string.equals("-")){
    
    
            return 0;
        }else if (string.equals("*")||string.equals("/")){
    
    
            return 1;
        }else {
    
    
            throw new RuntimeException("符号错误");
        }
    }

    //    计算后缀表达式
    public int GetResult(String str){
    
    
//        计算后缀表达式非常简单,先定义栈,然后对后缀表达式的集合进行遍历。若为数字则直接如栈,若为运算符,则从占中出栈两个元素根据此运算符进行运算,将运算结果再入栈。
//        循环此操作,最后留在栈中的那个元素则为原中缀表达式的结果
        List<String> list=ReturnRPN(ReturnList(str));
        Stack<String> stack=new Stack<String>();
        for (String string:list){
    
    
            if (string.matches("\\d+")){
    
    
                stack.push(string);
            }else {
    
    
                int num1=Integer.parseInt(stack.pop());
                int num2=Integer.parseInt(stack.pop());
                int num=operation(num1,num2,string);
                stack.push(num+"");
            }
        }
        return Integer.parseInt(stack.pop());  //转为整形
    }
    //    运算
    public int operation(int num1,int num2,String str){
    
    
        if (str.equals("+")){
    
    
            return num1+num2;
        }else if (str.equals("-")){
    
    
            return num2-num1;
        }else if (str.equals("*")){
    
    
            return num1*num2;
        }else if(str.equals("/")){
    
    
            return num2/num1;
        }else {
    
    
            throw new RuntimeException("运算出错");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_45821251/article/details/120163239