Java数据结构与算法:栈数据结构与前缀表达式、中缀表达式(思路分析、代码实现)


栈实现综合计算器运算


1、前缀表达式 (波兰表达式)

前缀表达式又称波兰表达式。运算符位于操作数之前。

比如:(3+2)*6-5 对应前缀表达式就是:- * + 3 2 6 5

. 思路分析

计算机从右至左扫描前缀表达式,依次将数字入栈。当遇到运算符,弹出栈顶和次顶两个数进行运算,运算结果再次入栈,遇到下一个运算符,又弹出栈顶和次顶两个数进行运算,运算结果再次入栈,依次类推…最终得到运算结果。

简单示例:

    • 3 2 6 5
  • 遇5,入栈
  • 遇6,入栈
  • 遇2,入栈
  • 遇3,入栈
  • 遇+,弹出栈顶和次顶两数,3和2进行运算,即3+2=5,5入栈
  • 遇*,弹出栈顶和次顶两数,5和6进行运算,即5*6=30,30入栈
  • 遇-,弹出栈顶和次顶两数,30和5进行运算,即30-5=25,25入栈
  • 最后栈中数即为结果。

2、中缀表达式

中缀表达式就是日常生活中经常使用的表达式,中缀表达式对于人来说是十分好理解的,但是对于计算机来说,操作起来十分麻烦,要去考虑运算符的优先级以及括号的情况等,还需要两个栈来辅助计算,大大增加了内存的开销。一般会将中缀表达式转为其他表达式进行运算操作。(一般转为后缀表达式)


. 思路分析

在这里插入图片描述

准备两个栈,一个数栈,一个符号栈。

入栈规则:

  • 从头开始依次遍历整个运算式子
  • 遇到数字直接入栈
  • 遇到符号:
    • 如果符号栈为空,那么直接入栈;
    • 如果要入栈的符号优先级别小于或等于栈顶的符号,那么就将符号栈栈顶的符号pop出来,再将数栈pop出两个数字进行运算,将运算结果放入数栈,再将要入栈的符号放入符号栈;
    • 如果要入栈的符号优先级别大于栈顶的符号,那么就直接入符号栈。
  • 最后依次将数栈的元素pop出来,符号栈的元素pop出来,顺序运算即可得到最终结果。

简单示例,建议根据描述画图理解:

6+2*5-3

步骤:

  • 遇到6,直接入数栈
  • 遇到+,符号栈中为空,直接入符号栈
  • 遇到2,直接入数栈
  • 遇到*,此时*与符号栈栈顶的+相比,*优先级别大于+,因此直接入符号栈
  • 遇到5,直接入数栈
  • 遇到-,此时-与符号栈栈顶的*号相比,-优先级别小于*,因此将*号pop出来,数栈pop两个数进行运算,即5*2=10,将10放入数栈,再将-号放入符号栈
  • 遇到3,直接入数栈
  • 此时已将式子遍历完,依次将数栈,符号栈pop出来运算
  • 数栈pop出3,符号栈-,数栈pop出10,运算:10-3=7 (当是-或者/,记住先出栈的为被减数或被除数),将结果放入数栈
  • 数栈pop出7,符号栈pop出+,数栈pop出6,运算:7+6=13,将结果放入数栈中,即最终结果

. 代码实现

不考虑括号运算符,只考虑加减乘除的整数运算,该代码只是用于理解栈和思路,计算器的实现代码仅供参考,不是最优解

public class InfixCalculator {
    public static void main(String[] args) {
        String expression = "60+2*50-3";

        if(!expression.isEmpty()){
            InfixStack numStack = new InfixStack(expression.length()); // 数栈
            InfixStack operStack = new InfixStack(expression.length()); // 符号栈

            int index = 0; // 用于遍历表达式
            String num = ""; // 用于存储数字
            int oper = 0; // 用于存储符号
            while (true){
                // 获取数字
                char oneChar = expression.charAt(index);
                num += oneChar;
                // 判断下一个字符是不是数字,是数字就加入到num中,不是就跳出
                while (true){
                    if(index < expression.length()-1){ // 判断是否越界
                        if(numStack.isNumber(expression.charAt(index+1))){
                            num += expression.charAt(index+1);
                            index++;
                        }else {
                            index++;
                            break;
                        }
                    }else {
                        break;
                    }
                }
                // 将数字结果放入数栈中
                numStack.push(Integer.parseInt(num));
                // 记录数字的字符串置空
                num = "";

                // 运算符获取
                if(index < expression.length()-1){
                    oper = expression.charAt(index);
                    if(!operStack.isEmpty()){
                        // 判断符号栈中的符号与要入栈符号的优先级别,优先级别小于或等于,
                        // 就进行运算操作,把运算结果放入数栈中
                        if(operStack.operPriority(oper) 
                           <= operStack.operPriority(operStack.peek())){
                            int num1 = numStack.pop();
                            int num2 = numStack.pop();
                            char operation = (char) operStack.pop();
                            int res = operStack.calculator(num1, num2, operation);
                            numStack.push(res);
                        }
                    }
                    // 如果符号栈为空或者优先级别大于栈顶符号,就直接入栈
                    operStack.push(oper);
                }else {
                    // 如果字符串已经遍历完了,就执行最后的运算,
                    // 符号栈中已经为空,说明已运算完
                    while (!operStack.isEmpty()){
                        int num1 = numStack.pop();
                        int num2 = numStack.pop();
                        char operation = (char) operStack.pop();
                        int res = operStack.calculator(num1, num2, operation);
                        numStack.push(res);
                    }
                    break;
                }

                index++;
            }

            System.out.println(expression+"="+numStack.pop());

        }else {
            System.out.println("表达式无效...");
        }

    }
}

class InfixStack{
    private int maxSize;
    private int top = -1;
    private int arr[];

    public InfixStack(int maxSize) {
        this.maxSize = maxSize;
        this.arr = new int[maxSize];
    }

    public boolean isFull(){
        return top == maxSize-1;
    }

    public boolean isEmpty(){
        return top == -1;
    }

    public int pop(){
        if(!isEmpty()){
            int value = arr[top];
            top--;
            return value;
        }else {
            throw new RuntimeException("栈空...");
        }
    }

    public boolean push(int val){
        if(!isFull()){
            top++;
            arr[top] = val;
            return true;
        }else {
            throw new RuntimeException("栈满...");
        }
    }

    public int peek(){
        if(!isEmpty()){
            return arr[top];
        }else {
            throw new RuntimeException("栈空...");
        }
    }

    public boolean isNumber(int num){
        if( (0<=num && num<=9) || ('0'<=num && num<='9')){
            return true;
        }else {
            return false;
        }
    }

    public int operPriority(int oper){
        if(oper == '*' || oper == '/'){
            return 1;
        }else if (oper == '+' || oper == '-'){
            return 0;
        }else {
            throw new RuntimeException("运算符有误...");
        }
    }

    public int calculator(int num1, int num2, char oper){
        int result = 0;
        switch (oper){
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num2 - num1;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                result = num2 / num1;
                break;
            default:
                break;
        }
        return result;
    }
}
60+2*50-3=157
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值