使用栈完成中缀表达式计算(java)

使用栈完成表达式的计算思路

先定义两个栈,一个栈存放操作数,另一个栈存放操作符号
1、通过一个index值(索引),来遍历表达式

2、如果index扫描到的是数字,就直接入数字栈

3、如果index扫描到的是一个符号,分如下情况:

3.1、如果当前的符号栈为空,就直接入栈

3.2、如果符号栈中有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符,就需要从数栈中pop中取出两个数,再从符号栈中pop中取出一个数,进行运算,将得到的结果入数栈,然后将当前的操作符入符号栈

3.3、如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈

4、当表达式扫描完毕后,就顺序的从数栈和符号栈中华会馆pop出相应的数字和符号,并进行运算;

5、最后在数栈中只有一个数字,就是表达式的计算结果

例子:
计算 3+2*6-2 的结果

过程:
①先创建两个栈,一个数栈,用来存放数字,一个符号栈,用来存放操作符号

②数栈刚开始为空,index扫描到的是数字3,则3直接入数栈

③index继续扫描,扫描到的是 + 号,且符号栈为空,直接入符号栈

④index继续扫描,扫描到数字 2 ,则直接入数栈

⑤index继续扫描,扫描到的是 * 号,且它的优先级比符号栈中的 + 号要高,所以直接入符号栈

⑥index继续扫描,扫描到的是数字6,则直接入数栈

⑦index继续扫描,扫描到的是 - 号, 且它的优先级比符号栈中的 *号要低,所以 - 号先不入栈,而是从数栈中取出两个数字,取出的是6和2,且从符号栈中取出一个符号,取出的是 * 号,进行计算,得到结果12,再把它压入到数栈中,此时再把 - 号入符号栈;

⑧index继续扫描,扫描到的是数字2,则直接入数栈

⑨此时表达式已经扫描完毕,就需要顺序的从数栈和符号栈中pop出相应的数字和符号,进行运算;
此时数栈中的元素分别是2,12,3,符号栈中的元素分别是 -+

⑩因为此时的表达式已经扫描完毕,所以要顺序地从数栈和符号栈中取出相应的数字和符号进行计算;

此时应该pop出数字 2 和 12 ,并且pop出运算符 -,这里需要注意的是, 2 和 12 进行剑法运算的时候,是==后pop出的元素对先pop出的元素进行运算 ==,也就是需要用 12 减去 2,得到的结果 10,再压入到数栈中;

11、最后,就是pop出数栈中的 10 和 3,并pop出符号栈中的 + 号,进行运算,3 + 10,得到结果13,此时符号栈已经为空,数栈中只剩下最后一个元素13,则 13 就是表达式的计算结果

代码实现如下:

public class Calculator {
    public static void main(String[] args) {
        //根据思路,完成表达式的计算
        String expression = "30+20*6-2";  //如何处理多位数的问题
        //创建两个栈,一个是数栈,一个是符号栈
        ArrayStack1 numStack = new ArrayStack1(10);
        ArrayStack1 operStack = new ArrayStack1(10);
        //定义需要的相关变量
        int index = 0;  //用于扫描
        int num1 = 0; 
        int num2 = 0;
        int oper = 0;
        int res = 0;
        char ch = ' ';  //将每次扫描得到的char保存到ch中

        String keepNum = "";  //用于拼接多位数

        //开始用while循环的扫描expression
        while (true) {
            //依 次得到expression的每一个字符
            //字符串中有一个函数是substring方法,两个参数分别是开始位置和结束位置,这里就是获取了一个字符的字符串
            //substring获取到的是字符串,但是ch是char类型,只能接收一个字符,所以用charAt来获得substring字符串中的其中一个字符
            ch = expression.substring(index, index + 1).charAt(0);
            //判断ch是什么,然后做相应的处理
            if (operStack.isOper(ch)) {  //如果是运算符
                //判断当前的符号栈是否为空
                if (!operStack.isEmpty()) {
                    //如果符号栈中有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符,就需要从数栈中取出两个数
                    //并在符号栈中取出一个符号,进行运算,将得到的结果,入数栈,然后将当前的操作符入符号栈
                    if (operStack.priority(ch) <= operStack.priority(operStack.peek())) {
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        res = numStack.cal(num1, num2, oper);
                        //把运算的结果加入到数栈中
                        numStack.push(res);
                        operStack.push(ch);
                    }
                    else {  //如果当前的操作符的优先级大于栈中的操作符,就直接入栈
                        operStack.push(ch);
                    }
                }
                else {   //如果符号栈为空,直接入栈
                    operStack.push(ch);
                }
            }
            else {  //如果是数字,直接入数栈
                //分析思路:
                //1.当处理多位数时,不能发现是一个数的时候就直接入栈,因为它可能是多位数,
                //2.在处理数时,需要向expression的表达式的index后再看一位,如果是数就进行扫描,如果是符号才入栈
                //3.因此需要定义一个字符串变量,用于拼接
                keepNum += ch;

                //如果ch已经是expression的最后一位,就直接入数栈
                if (index == expression.length() - 1) {
                    numStack.push(Integer.parseInt(keepNum));
                }
                else {
                    //判断下一个字符是不是数字,如果是数字,就继续扫描,如果是运算符,就入数栈
                    //注意是往后看一位,不是index++
                    if (operStack.isOper(expression.substring(index+1,index+2).charAt(0))) {
                        //如果后一位是运算符,则入栈,但是keepNum是一个字符串,需要把它转换成整型才可以,所以可以调用Integer.parseInt方法,把keepNum转换成整型
                        numStack.push(Integer.parseInt(keepNum));
                        //重要!!!,keepNum需要清空
                        keepNum = "";
                    }
                }
            }
            //让index + 1,并判断是否扫描到了expression的最后
            index++;
            if (index >= expression.length()) {
                break;
            }

        }
        //当表达式扫描完毕,就顺序的从数栈和符号栈中pop出相应的数字和符号,并运行
        while (true) {
            //如果符号栈为空,则计算已经结束,数栈中只有一个数字【结果】
            if (operStack.isEmpty()) {
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operStack.pop();
            res = numStack.cal(num1, num2, oper);
            numStack.push(res);  //入栈
        }
        //将数栈中最后的数字pop出,就是表达式的计算结果
        int res2 = numStack.pop();
        System.out.printf("表达式 %s = %d\n", expression, res2);
    }
}

//先创建一个栈,这里用数组来模拟栈的实现
class ArrayStack1 {
    private int maxSize;  //栈的大小
    private int[] stack1;  //数组,数组模拟战,数据就存放在该数组当中
    private int top = -1;  //top表示栈顶,初始化为-1

    //构造器
    public ArrayStack1(int maxSize) {
        this.maxSize = maxSize;
        stack1 = 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;
        }
        top++;
        stack1[top] = value;
    }

    //出栈
    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("栈空,没有数据");

        }
        int value = stack1[top];
        top--;
        return value;
    }

    //返回当前的栈顶的值,但不出栈
    public int peek() {
        return stack1[top];
    }

    //遍历栈
    public void list() {
        if (isEmpty()) {
            System.out.println("栈空,无法进行遍历操作");
            return;
        }
        for (int i = top; i >= 0; i--) {
            System.out.printf("%d\t", stack1[i]);
        }
        System.out.println();
    }

    //返回运算符的优先级,优先级的顺序是由用户来决定的,优先级使用数字来表示
    //数字越大,表示优先级越高
    public int priority(int oper) {
        if (oper == '*' || oper == '/') {
            return 1;
        } else if (oper == '+' || oper == '-') {
            return 0;
        } else {
            return -1;  //假定目前的表达式中只含有 +,-,*,/
        }
    }

    //判断是否是一个运算符
    public boolean isOper(char val) {
        return val == '+' || val == '-' || val == '*' || val == '/';
    }

    //计算方法
    public int cal(int num1, int num2, int oper) {
        int res = 0; //res用于存放计算的结果
        switch (oper) {
            case '+':
                res = num1 + num2;
                break;
            case '-':
                res = num2 - num1;  //注意顺序
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                res = num2 / num1;
                break;
            default:
                break;
        }
        return res;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值