青训营X豆包MarsCode 技术训练营第二课 | 豆包MarsCode AI 刷题

40 阅读3分钟

青训营X豆包MarsCode 技术训练营第二课 | 豆包MarsCode AI 刷题

在编程的学习和实践中,实现一个基本计算器是一个里程碑式的项目。它不仅考验我们对基础语法的掌握,还挑战我们对算法和数据结构的理解。本文将深入探讨如何从零开始构建一个基本计算器,以及在这个过程中的思考和学习。

问题描述

我们的目标是实现一个计算器,它能够解析和计算包含基本算术运算符(加、减、乘、除)和括号的字符串表达式。这个任务要求我们处理不同的数据类型(数字和字符),并实现一个能够理解运算优先级的解析器。

问题分析

这个问题的关键在于如何有效地处理运算符的优先级和括号。在没有使用内置的eval函数的情况下,我们需要自己实现一个解析算法。栈数据结构在这里扮演了核心角色,因为它能够帮助我们管理运算符的顺序和优先级。

算法选择

我们选择了两个栈的算法:一个用于存储操作数(值栈),另一个用于存储操作符(运算符栈)。这种算法被称为“逆波兰表示法”或“后缀表示法”,它允许我们通过栈来简化计算过程。

代码实现

以下是Java语言实现的核心代码:

 import java.util.*;
 ​
 public class Main {
     private static int precedence(char op) {
         switch (op) {
             case '+': case '-': return 1;
             case '*': case '/': return 2;
             default: return 0;
         }
     }
 ​
     private static int applyOp(int a, int b, char op) {
         switch (op) {
             case '+': return a + b;
             case '-': return a - b;
             case '*': return a * b;
             case '/': return a / b;
         }
         return 0;
     }
 ​
     public static int solution(String tokens) {
         Stack<Integer> values = new Stack<>();
         Stack<Character> ops = new Stack<>();
 ​
         for (int i = 0; i < tokens.length(); i++) {
             char c = tokens.charAt(i);
             if (Character.isDigit(c)) {
                 int val = 0;
                 while (i < tokens.length() && Character.isDigit(tokens.charAt(i))) {
                     val = val * 10 + (c - '0');
                     i++;
                 }
                 i--;
                 values.push(val);
             } else if (c == '(') {
                 ops.push(c);
             } else if (c == ')') {
                 while (!ops.isEmpty() && ops.peek() != '(') {
                     values.push(applyOp(values.pop(), values.pop(), ops.pop()));
                 }
                 ops.pop();
             } else {
                 while (!ops.isEmpty() && precedence(ops.peek()) >= precedence(c)) {
                     values.push(applyOp(values.pop(), values.pop(), ops.pop()));
                 }
                 ops.push(c);
             }
         }
 ​
         while (!ops.isEmpty()) {
             values.push(applyOp(values.pop(), values.pop(), ops.pop()));
         }
 ​
         return values.pop();
     }
 ​
     public static void main(String[] args) {
         System.out.println(solution("3+4*5/(3+2)")); // 输出 7
     }
 }

个人思考

在实现计算器的过程中,我深刻体会到了算法的力量。每一个决策,无论是选择数据结构还是设计算法流程,都直接影响了程序的性能和准确性。我也认识到了测试的重要性,因为只有通过全面的测试,我们才能确保我们的计算器能够处理各种复杂的情况。

此外,我也意识到了代码的可读性和可维护性。良好的代码结构和注释能够帮助他人(或未来的自己)更好地理解代码的意图和逻辑。

结语

通过构建一个基本计算器,我们不仅能够提升编程技能,还能加深对算法和数据结构的理解。希望这篇文章能够帮助你更好地理解如何实现一个基本计算器,并在编程学习中取得进步。通过不断的实践和学习,我们可以在技术领域不断成长和进步。