数据结构与算法: 使用栈解决计算器问题

该篇博客介绍了如何使用Java实现一个计算器,通过栈来处理中缀表达式,包括支持加减乘除、括号和小数点。博客详细讲解了中缀表达式转后缀表达式的过程,并提供了两个案例,一个是无括号的计算,另一个涉及括号的优先级处理。博主给出了完整的代码实现,包括栈的模拟和计算过程,帮助读者理解计算器算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构与算法:使用栈解决计算器问题

Tips: 采用java语言, 关注博主,底部附有完整代码

使用到的知识点:

  • 中后缀表达式
  • 后缀表达式
  • 中缀表达式转后缀表达式

支持范围: + - * / 小括号() 小数点

例如: 
案例一: 20 - 5 + 25 / 5 + 20 / 5 + 100 - 24 - 0.4
案例二: (3 + 5 + 2.5) - 2 * 5 

效果图

案例一案例二
gif_1gif_2

案例二思路分析图:

中缀to后缀

案例一(不带括号)

注释我写的很详细,直接看完整代码:

/**
 * @author: android 超级兵
 * @create: 2022-05-07 11:08
 * TODO 使用栈来解决计算器计算问题
 **/
public class Client {
    public static void main(String[] args) {

        // 结果 = 100
        String str = "20-5+25/5+20/5+100-24-0.4";
        // 用来存放数字
        CalculatorStack numberStack = new CalculatorStack(str.length());
        // 用来存放符号
        CalculatorStack operatorStack = new CalculatorStack(str.length());

        // 解析公式
        List<String> parse = parseInfixFormula(str);

        // 循环每一次 合理的入栈
        for (String value : parse) {
            if (value == null) {
                continue;
            }

            // 判断是否是数字
            if (isNumber(value)) {
                // 数字
                numberStack.push(Float.parseFloat(value));
            } else {
                // 符号

                char operator = value.charAt(0);
//                System.out.println("符号:" + operator);

                // 判断符号栈是否为null
                if (operatorStack.isEmpty()) {
                    // 符号第一次加载的时候 直接添加进去
                    operatorStack.push(operator);
                } else {
                    // 不是第一次加载

                    // 先判断优先级
                    if (getLevel(operator) < getLevel((char) operatorStack.seeHeadData())) {
                        // 如果当前优先级 < 顶部的优先级
                        // 例如 即将添加的符号为 + , 顶部的符号为 *
                        // 那么先取出数栈中2个数,和符号栈中一个数 计算
                        // 最终将计算结果在添加到数栈中...

                        float num1 = numberStack.pop();
                        float num2 = numberStack.pop();
                        char oper = (char) operatorStack.pop();
                        float result = result(num1, num2, oper);
                        System.out.printf("先计算:%.1f %c %.1f = %.1f\n", num2, oper, num1, result);
                        numberStack.push(result);
                        operatorStack.push(operator);
                    } else {
                        // 如果优先级相等 则直接加入
                        operatorStack.push(operator);
                    }
                }
            }
        }

        // 反转数据!
        numberStack.reverse();
        operatorStack.reverse();

        // 计算最终结果
        while (!operatorStack.isEmpty()) {
            float num1 = numberStack.pop();
            float num2 = numberStack.pop();
            char operator = (char) operatorStack.pop();
            float result = result(num2, num1, operator);
            System.out.printf("计算:%.1f %c %.1f = %.1f\n", num1, operator, num2, result);
            numberStack.push(result);
        }

        System.out.println("最终结果为:" + str + " = " + numberStack.seeHeadData());
    }
}

使用数组模拟栈

/**
 * @author: android 超级兵
 * @create: 2022-05-07 11:10
 **/
public class CalculatorStack {

    // 用来存放数据
    float[] mStacks;

    // top的坐标
    int currentIndex = -1;

    /**
     * @param max 栈的最大值
     */
    public CalculatorStack(int max) {
        mStacks = new float[max];
    }

    public synchronized void push(float value) {
        // 判断栈是否满
        if (isFull()) {
            System.out.println("栈满了~~");
            return;
        }


        currentIndex++;
        mStacks[currentIndex] = value;
    }

    // 懒的判断是否为null了
    public float seeHeadData() {
        try {
            return mStacks[currentIndex];
        } catch (Exception e) {
            return 0;
        }
    }

    // 弹出
    public synchronized float pop() {
        if (isEmpty()) {
            throw new NullPointerException("栈空了");
        }
        float value = mStacks[currentIndex];
        mStacks[currentIndex] = 0;
        currentIndex--;
        return value;
    }

    public synchronized void show() {
        for (int i = mStacks.length - 1; i >= 0; i--) {
            if (mStacks[i] != 0) {
                System.out.println(mStacks[i]);
            }
        }
        System.out.println();
    }

    public void showChar() {
        for (int i = mStacks.length - 1; i >= 0; i--) {
            if (mStacks[i] != 0) {
                System.out.println((char) mStacks[i]);
            }
        }
        System.out.println();
    }

    /*
     * @author: android 超级兵
     * @create: 2022/5/7 18:09
     * TODO 反转数据
     */
    public synchronized void reverse() {
        float[] tempInts = new float[mStacks.length];

        int index = 0;
        while (!isEmpty()) {
            tempInts[index++] = pop();
        }

        for (float value : tempInts) {
            if (value != 0) {
                push(value);
            }
        }
    }

    /*
     * @author: android 超级兵
     * @create: 2022/5/7 11:15
     * TODO 是否栈满
     */
    public boolean isFull() {
        return currentIndex == mStacks.length;
    }

    /*
     * @author: android 超级兵
     * @create: 2022/5/7 11:15
     * TODO 是否栈空
     */
    public boolean isEmpty() {
        return currentIndex == -1;
    }
}

运行结果:

先计算:25.0 / 5.0 = 5.0
先计算:20.0 / 5.0 = 4.0
计算:20.0 - 5.0 = 15.0
计算:15.0 + 5.0 = 20.0
计算:20.0 + 4.0 = 24.0
计算:24.0 + 100.0 = 124.0
计算:124.0 - 24.0 = 100.0
计算:100.0 - 0.4 = 99.6
最终结果为:20-5+25/5+20/5+100-24-0.4 = 99.6

案例二(带括号)

/**
 * @author: android 超级兵
 * @create: 2022-05-09 00:43
 * TODO 解决计算器中带有括号的优先级
 * 例如: 中缀表达式: ( 3 + 4 ) * 5 - 6 = 29
 * 后缀表达式:  3 4 + 5 * 6 -
 **/
public class Client {
    public static void main(String[] args) {

//        后缀
//        String formula = "3 4 + 5 * 6 -";
//        // 解析后缀表达式
//        List<String> str = FormulaUtil.parseSuffixFormula(formula);

        // 中缀
        String formula = "(3 + 5 + 2.5) - 2 * 5";
        // 中缀 转 后缀
        List<String> str = FormulaUtil.inFixToSuffix(formula);

        Stack<String> numberStack = new Stack<>();

        for (String item : str) {
            if (FormulaUtil.isNumber(item)) {
                // 数字
//                System.out.println("数字:" + item);
                // 数字直接入栈
                numberStack.push(item);
            } else {
                // 符号
//                System.out.println("符号:" + item);
                float number1 = Float.parseFloat(numberStack.pop());
                float number2 = Float.parseFloat(numberStack.pop());
                char oper = item.charAt(0);
                float res = FormulaUtil.result(number1, number2, oper);
                System.out.printf("计算:%.1f %c %.1f = %.1f\n", number2, oper, number1, res);
                numberStack.push(String.valueOf(res));
            }
        }
        System.out.println("最终结果为:" + numberStack.pop());
    }
}

FormulaUtil 辅助类

/**
 * @author: android 超级兵
 * @create: 2022-05-09 00:48
 * TODO 公式辅助类
 **/
public class FormulaUtil {

    /*
     * @author: android 超级兵
     * @create: 2022/5/9 01:21
     * TODO 中缀转后缀
     * 例如 (3 + 5) * 2 - 5 => 3 5 + 2 * 5 -
     * (4 + (8 - 5) * 3 - 5 => 4 8 5 - + 3 * 5 -
     */
    public static List<String> inFixToSuffix(String infix) {

        List<String> infixList = parseInfixFormula(infix);

        // 存放符号元素
        Stack<String> elementStack = new Stack<>();

        // 存放符号 + 数字元素
        ArrayList<String> elementList = new ArrayList<>();


        for (String item : infixList) {
            if (isNumber(item)) {
                // 数字
                elementList.add(item);
            } else if (item.equals("(")) {
                elementStack.push(item);
            } else if (item.equals(")")) {
                while (!elementStack.peek().equals("(")) {
                    String pop = elementStack.pop();
                    elementList.add(pop);
                }
                // 弹出 )
                elementStack.pop();
            } else {
                // 符号
//                System.out.println("符号为:" + item);


                if (elementStack.size() != 0 && getLevel(elementStack.peek().charAt(0)) > getLevel(item.charAt(0))) {
                    // 如果 栈顶等级 > 当前符号的等级
                    elementList.add(elementStack.pop());
                }

                // 将当前符号压入栈中
                elementStack.push(item);
            }
        }

        // 将 elementStack 中剩余元素 添加到 elementList中
        while (elementStack.size() != 0) {
            elementList.add(elementStack.pop());
        }

        System.out.println("中缀为:" + infix);
        System.out.println("中缀转后缀最终结果为:");
        for (String o : elementList) {
            System.out.println(o);
        }
        return elementList;
    }

    /*
     * @author: android 超级兵
     * @create: 2022/5/9 01:05
     * TODO 解析后缀表达式 例如str = "3 4 + 5 * 6 -";
     * 解析后:
     * 3
     * 4
     * +
     * 5
     * *
     * 6
     * -
     * tips: 注意后缀表达式格式,每个元素之间空格隔开!
     */
    public static List<String> parseSuffixFormula(String str) {
        return Arrays.asList(str.split(" "));
    }

    /*
     * @author: android 超级兵
     * @create: 2022/5/7 15:41
     * TODO 解析中缀表达式 例如 str = "62-5+25/5";
     * 解析后:
     *  62
     *  -
     *  5
     *  +
     *  25
     *  /
     *  5
     */
    public static ArrayList<String> parseInfixFormula(String str) {
        StringBuilder temp = new StringBuilder();
        ArrayList<String> numbers = new ArrayList<>();

        // 消除所有的空格
        str = str.replaceAll(" ", "");

        for (int i = 0; i < str.length(); i++) {
            char indexValue = str.charAt(i);

            // 判断是否是符号
            if (isOperator(indexValue)) {
//                System.out.println("符号:" + indexValue);
                // 是符号
                numbers.add(String.valueOf(indexValue));
            } else {
                // 是数字
//                System.out.println("数字:" + indexValue);

                int check = (int) indexValue - 48;
                // 46代表小数点
                // ASCII码对照表: https://www.habaijian.com/
                if ((check < 0 || check > 9) && indexValue != 46) {
                    throw new RuntimeException("存在特殊符号");
                }

                // 是否是最后一位数字
                if (i == str.length() - 1) {
                    // 直接添加
                    numbers.add(String.valueOf(temp) + indexValue);
                } else {
                    // 如果不是符号,则一直记录
                    temp.append(indexValue);
                    // 判断下一位是否是符号
                    if (isOperator(str.charAt(i + 1))) {
                        // 符号
                        numbers.add(temp.toString());
                        // 清空stringBuilder
                        temp = new StringBuilder();
                    }
                }
            }
        }
        System.out.println("解析完成:");
        for (String number : numbers) {
            if (null != number) {
                System.out.println(number);
            }
        }
        System.out.println();
        return numbers;
    }

    /**
     * TODO 是否是符号(+ , - , * , /)
     */
    public static boolean isOperator(char value) {
        return value == '+'
                || value == '-'
                || value == '*'
                || value == '/'
                || value == '('
                || value == ')'
                ;
    }

    /*
     * @author: android 超级兵
     * @create: 2022/5/7 17:27
     * TODO 用来计算结果
     */
    public static float result(float num1, float num2, char operator) {
        switch (operator) {
            case '+':
                return num2 + num1;
            case '-':
                return num2 - num1;
            case '*':
                return num2 * num1;
            case '/':
                return num2 / num1;
            default:
                return 0;
        }
    }

    /*
     * @author: android 超级兵
     * @create: 2022/5/7 17:16
     * TODO 判断是否是数字
     */
    public static boolean isNumber(String str) {
        try {
            Float.parseFloat(str);
            return true;
        } catch (NumberFormatException e) {

            return false;
        }
    }

    /*
     * @author: android 超级兵
     * @create: 2022/5/7 17:10
     * TODO 根据符号判断级别
     * 例如输入 *
     *  返回 2
     */
    public static int getLevel(char value) {
        switch (value) {
            case '*':
            case '/':
                return 2;

            case '+':
            case '-':
                return 1;

            default:
                return -1;
        }
    }
}

完整代码

原创不易,您的点赞就是对我最大的支持 !

关注博主,敬请期待更多数据结构与算法 !

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

s10g

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值