最近在刷算法題時,遇到了實現計算器的問題。一開始覺得很簡單,但真正動手實現時才發現其中有很多細節需要考慮。今天就來分享一下我的實現思路和學到的經驗。
問題分析
我們需要實現一個能夠處理加減乘除四則運算的計算器,要正確處理運算符的優先級(乘除優先于加減),同時還要處理空格和多位數字。
解決方案:中綴表達式轉后綴表達式
我選擇的方法是中綴表達式轉后綴表達式(逆波蘭表達式),然后再計算后綴表達式。這種方法雖然需要兩個步驟,但邏輯清晰,易于理解和實現。
第一步:中綴轉后綴
cpp
int calculate(string s) {vector<string> postfix; // 存儲后綴表達式stack<string> opStack; // 運算符棧for (int i = 0; i < s.size();) {// 跳過空格if (s[i] == ' ') {i++;continue;}// 處理數字if (isdigit(s[i])) {string num;while (i < s.size() && isdigit(s[i])) {num += s[i++];}postfix.push_back(num);} // 處理運算符else {string op(1, s[i++]);// 處理運算符優先級if (op == "+" || op == "-") {// 加減優先級最低,彈出所有運算符while (!opStack.empty()) {postfix.push_back(opStack.top());opStack.pop();}opStack.push(op);} else if (op == "*" || op == "/") {// 乘除優先級較高,只彈出同優先級的運算符while (!opStack.empty() && (opStack.top() == "*" || opStack.top() == "/")) {postfix.push_back(opStack.top());opStack.pop();}opStack.push(op);}}}// 彈出棧中剩余的所有運算符while (!opStack.empty()) {postfix.push_back(opStack.top());opStack.pop();}return evalRPN(postfix); }
第二步:計算后綴表達式
cpp
int evalRPN(vector<string>& tokens) {stack<int> st;for (auto& e : tokens) {if (isdigit(e[0]) || (e.size() > 1 && e[0] == '-')) {st.push(stoi(e));} else {int n1 = st.top(); st.pop();int n2 = st.top(); st.pop();switch (e[0]) {case '+': st.push(n2 + n1); break;case '-': st.push(n2 - n1); break;case '*': st.push(n2 * n1); break;case '/': if (n1 == 0) throw runtime_error("Division by zero");st.push(n2 / n1); break;}}}return st.top(); }
遇到的坑和解決方案
1. 多位數字的處理
最初我忽略了數字可能有多位的情況,導致?123
?被識別為三個單獨的數字?1
、2
、3
。解決方法是在遇到數字時持續讀取直到非數字字符。
2. 運算符優先級
加減乘除的優先級不同,需要特殊處理:
遇到?
+
?或?-
?時,彈出棧中所有運算符(因為加減優先級最低)遇到?
*
?或?/
?時,只彈出同優先級的運算符
3. 空格處理
用戶輸入可能包含空格,需要在讀取時跳過這些空格字符。
4. 除零錯誤
在除法運算時添加了除零檢查,避免程序崩潰。
寫代碼就像搭積木,有時候看似復雜的結構,拆解開來都是簡單的基礎模塊。保持思考,持續學習,共勉!