使用栈模拟完整版计算器

使用栈模拟完整版计算器

说明

  1. 此计算器可以计算常用的 + - * / ( ) ,但没有考虑小数点
  2. 若想实现小数的计算,可自行实现

思路分析:

  1. 将中缀表达式各元素先存储到集合
  2. 然后将中缀表达式转换为后缀表达式
  3. 进行后缀表达式的计算

源码及分析

package algorithm.stack_;

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

/**
 * @author AIMX_INFO
 * @version 1.0
 */
@SuppressWarnings("all")
public class CompleteCalculator {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.print("请输入你要计算的表达式: ");
            String expression = scanner.nextLine();
            //去空格
            for (int i = 0; i < 10; i++) {
                expression = expression.replace(" ", "");
            }
            expression = expression.replace("=","");
            //中缀表达式存入集合
            List<String> infixExpressionList = infixExpressionToList(expression);
            System.out.println("中缀 : " + infixExpressionList);
            //中缀表达式转后缀
            List<String> sufixList = infixParseSufixList(infixExpressionList);
            System.out.println("后缀 : " + sufixList);
            //后缀表达式计算
            int res = calculate(sufixList);
            System.out.println(expression + " = " + res);
        }
    }
    /**
     * 编写后缀表达式的计算方法
     *
     * @param list 集合中保存要计算的数字和操作符
     * @return 计算的结果
     */
    public static int calculate(List<String> list) {
        //定义栈用来辅助计算
        Stack<String> stack = new Stack<>();
        //遍历集合
        for (String item : list) {
            //使用正则判断遍历出的是数字还是符号
            if (item.matches("\\d+")) {
                //如果是数字,则直接入栈
                stack.push(item);
            } else {
                //如果是符号,则从栈中弹出两个数进行计算
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                //调用计算的方法
                int res = calculateByNumAndOperation(num2, num1, item.charAt(0));
                //将计算的结果再入栈
                stack.push(res + "");
            }
        }
        //运算结束后留在栈底的就是计算的结果,返回即可
        return Integer.parseInt(stack.pop());
    }

    /**
     * 通过数字和操作符计算的方法
     *
     * @param num1      数字1
     * @param num2      数字2
     * @param operation 运算符
     * @return 计算的结果
     */
    public static int calculateByNumAndOperation(int num1, int num2, char operation) {
        //定义变量保存运算返回的结果
        int res = 0;
        switch (operation) {
            case '+':
                res = num1 + num2;
                break;
            //减法注意运算顺序
            case '-':
                res = num2 - num1;
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                //除法也要注意运算顺序
                res = num2 / num1;
                break;
            default:
                throw new RuntimeException("运算符有误~~");
        }
        return res;
    }
    //编写方法将中缀表达式转换为后缀表达式,方便计算机的计算
    //已将中缀表达式个元素存储到集合中,则只需要转换为后缀表达式存储到集合即可
    /**
     *
     * @param ls 中缀表达式所在集合
     * @return    返回后缀表达式
     */
    public static List<String> infixParseSufixList(List<String> ls){
        //定义一个栈用来辅助转换,基于栈的先进后出特性
        Stack<String> stack = new Stack<>();
        //定义集合保存转换后的后缀表达式
        List<String> list = new ArrayList<>();
        //遍历中缀表达式的所有元素,按照指定规则将其加入到集合中
        for (String item : ls) {
            //使用正则判断取出来的元素,如果取出来的是数字,则直接加入到集合
            if (item.matches("\\d+")){
                list.add(item);
                //如果是左括号,则直接入栈
            }else if (item.equals("(")){
                stack.push(item);
                //如果是右括号,则弹出栈中左括号之前的元素,因为考虑到小括号的优先级比其他运算符高
            }else if (item.equals(")")){
                while (!stack.peek().equals("(")){
                    list.add(stack.pop());
                }
                //最后再弹出左括号
                stack.pop();
                //否则是其他运算符的话就要比较运算符的优先级
            }else {
                //将高运算符先加入集合,因为要先进行计算
                while (stack.size() != 0 && Operation.getOperation(stack.peek()) >= Operation.getOperation(item)){
                    list.add(stack.pop());
                }
                //如果是优先级较低的运算符,则直接入栈
                stack.push(item);
            }
        }
        //最后将栈中所有的运算符全部出栈加入到集合中
        while (!stack.isEmpty()){
            list.add(stack.pop());
        }
        return list;
    }


    //编写方法将一个中缀表达式存储到集合中
    public static List<String> infixExpressionToList(String infixExp) {
        //定义ArrayList保存中缀表达式的各元素
        ArrayList<String> list = new ArrayList<>();
        //定义变量
        //定义扫描字符串的指针
        int i = 0;
        //定义字符串str用来拼接数字
        String str = "";
        //定义 c 表示当前扫描到的字符
        char c;
        //循环扫描字符串
        do {
            //如果当前扫描到的字符是一个非数字,即是一个运算符,则直接添加到List中
            if ((c = infixExp.charAt(i)) < 48 || (c = infixExp.charAt(i)) > 57) {
                list.add(c + "");
                i++;
            } else {
                //否则扫描到的就是一个数字,需要考虑多位数的情况
                //先将str置空
                str = "";
                //循环判断当前数字的下一位是否任然是数字,如果是,则拼接,否则结束循环
                while (i < infixExp.length() && (c = infixExp.charAt(i)) >= 48 && (c = infixExp.charAt(i)) <= 57) {
                    str += infixExp.charAt(i);
                    i++;
                }
                list.add(str);
            }
        } while (i < infixExp.length());
        return list;
    }

}
//编写一个类,返回运算符对应的优先级
@SuppressWarnings("all")
class Operation2{
    private static int ADD = 1;
    private static int SUB = 1;
    private static int MUL = 2;
    private static int DIV = 2;
    //编写方法返回运算符的优先级
    public static int getOperation(String operation){
        int res = 0;
        switch (operation){
            case "+":
                res = ADD;
                break;
            case "-":
                res = SUB;
                break;
            case "*":
                res = MUL;
                break;
            case "/":
                res = DIV;
                break;
            default:
                //System.out.println("运算符有误...");
                break;
        }
        return res;
    }
}

posted @ 2021-05-29 11:25  mx_info  阅读(110)  评论(0)    收藏  举报