栈模拟计算器

栈模拟计算器

  计算器是我们生活中最常见的数学用具,计算器可以用栈来模拟。
模拟计算器要点:

  1. 使用两个栈分别来存储数字和运算符以及括号。
  2. 遍历表达式字符串,分别处理’(’,’)’,运算符和数字。 如果是 ‘(’ 则直接入栈, 如果是 ‘)’ 则计算括号中的结果,如果是运算符则根据前一个操作符判断要计算还是直接入栈,如果是数字则根据表达式后一位判断要入栈还是继续读取数字拼接。
  3. 遍历完字符串后,清空运算符栈,计算最终结果。

下面代码演示一下:

import java.util.Stack;
import java.util.Scanner;

public class Calculator {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String expression = sc.next();     // 表达式
            if (expression.equals("end")) // 输入 end 结束
                break;
            System.out.printf("%s = %d\n", expression, count(expression));
        }
    }

    // 计算表达式
    public static int count(String expression) {
        Stack<Integer> numStack = new Stack();       // 存放数字的栈
        Stack<Character> operStack = new Stack();    // 存放运算符的栈
        int num1 = 0, num2 = 0, res = 0;
        char ch = ' ', oper = ' '; // ch是表达式中的每一字符,oper是运算符
        String number = "";  // 用于拼接多位数
        // 遍历字符串
        for (int i = 0; i < expression.length(); i++) {
            ch = expression.charAt(i);
            if (ch == '(') { // 如果是左括号直接入栈即可
                operStack.push(ch);
            } else if (ch == ')') { // 如果是有括号,处理括号里面的所有内容
                while (true) {
                    // 如果符号栈为'('
                    if (operStack.peek() == '(') {
                        operStack.pop();
                        break;
                    }
                    num1 = numStack.pop();
                    num2 = numStack.pop();
                    oper = operStack.pop();
                    res = calculate(num1, oper, num2);
                    numStack.push(res);  // 把运算结果入栈
                }
            } else if (isOper(ch)) { // 如果是运算符
                // 如果运算符栈为空时,该操作符直接入栈
                if (operStack.isEmpty() || operStack.peek() == '(') { // 利用惰性
                    operStack.push(ch);
                } else { // 如果运算符栈不为空或'('时,则需要判断要不要计算
                    // 如果当前运算符ch优先级小于或等于前一个运算符,需先计算前一个运算符
                    if (priority(ch) <= priority(operStack.peek())) {
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        res = calculate(num1, oper, num2);
                        numStack.push(res);  // 把运算结果入栈
                        operStack.push(ch);  // 把当前运算符压入栈
                    } else { // 如果当前运算符ch优先级大于前一个运算符,直接入栈
                        operStack.push(ch);
                    }
                }
            } else { // 如果是数字直接入栈
                number += ch;
                // 如果已经是最后一位了
                if (i == expression.length() -1) {
                    numStack.push(Integer.parseInt(number));
                } else if(isOper(expression.charAt(i+1)) || expression.charAt(i+1) == '(' || expression.charAt(i+1) == ')') {
                    numStack.push(Integer.parseInt(number));
                    number = "";
                }
            }
        }
        // 表达式遍历结束,清理栈
        while (true) {
            // 如果符号栈为空,退出
            if (operStack.isEmpty()) {
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operStack.pop();
            res = calculate(num1, oper, num2);
            numStack.push(res);  // 把运算结果入栈
        }
        // 此时数字栈中只剩下一个数字,也就是最终的计算结果,返回即可
        return numStack.pop();
    }

    // 判断优先级
    public static int priority(char oper) {
        if (oper == '*' || oper == '/')
            return 1;
        else if (oper == '+' || oper == '-')
            return 0;
        else
            return -1;
    }

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

    // 返回计算结果
    public static int calculate(int num1, char oper, int num2) {
        int res = 0;
        switch (oper) {
            case '+':
                res += num2 + num1;break;
            case '-':
                res += num2 - num1;break;
            case '*':
                res += num2 * num1;break;
            case '/':
                res += num2 / num1;break;
            default:
                break;
        }
        return res;
    }

}

测试一下,这里用两组数据,12*(2-5+1)/2+24,2+(22*6-10)/2 测试,以end结束,运行结果为:

12*(2-5+1)/2+24
12*(2-5+1)/2+24 = 12
2+(22*6-10)/2
2+(22*6-10)/2 = 63
end

上述是对中缀表达式的计算,想了解波兰表达式和逆波兰表达式可看
波兰计算器和逆波兰计算器

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值