四則運算的C++實現
阿新 • • 發佈:2019-02-17
一個很基本的問題,總是在重複發明輪子,為了不總討論這種月經問題,今天徹底終結這個問題吧。
大體分兩步:去掉括號,並轉化為字尾佇列,然後計算這個佇列
BaseCalc.h:
#pragma once enum CalcType { CalcType_None, CalcType_Number, CalcType_Operator_Plus, CalcType_Operator_Multiply, CalcType_Operator_Left_Parenthesis, CalcType_Operator_Minus = 0x80000000 + CalcType_Operator_Plus, CalcType_Operator_Divide = 0x80000000 + CalcType_Operator_Multiply, }; class CBaseCalc { public: CBaseCalc(char cOpr) { m_nValue = cOpr; if ('+' == cOpr) m_nType = CalcType_Operator_Plus; else if ('*' == cOpr) m_nType = CalcType_Operator_Multiply; else if ('(' == cOpr) m_nType = CalcType_Operator_Left_Parenthesis; else if ('-' == cOpr) m_nType = CalcType_Operator_Minus; else if ('/' == cOpr) m_nType = CalcType_Operator_Divide; else m_nType = CalcType_None; } CBaseCalc(CalcType nType){ m_nType = nType; m_nValue = 0; } virtual ~CBaseCalc(){} double GetValue(){ return m_nValue; } void SetValue(double d){ m_nValue = d; } CalcType GetType(){ return m_nType; } private: double m_nValue; CalcType m_nType; }; double Calculate(CalcType nType,CBaseCalc& a, CBaseCalc&b) { double dRet = 0; switch (nType) { case CalcType_None: break; case CalcType_Number: break; case CalcType_Operator_Plus: return a.GetValue() + b.GetValue(); break; case CalcType_Operator_Multiply: return a.GetValue() * b.GetValue(); break; case CalcType_Operator_Left_Parenthesis: break; case CalcType_Operator_Minus: return a.GetValue() -b.GetValue(); break; case CalcType_Operator_Divide: return a.GetValue() /b.GetValue(); break; default: break; } return dRet; } bool operator <(CBaseCalc& a, CBaseCalc& b) { int nA = a.GetType() & 0x7FFFFFFF; int nB = b.GetType() & 0x7FFFFFFF; return nA<nB; }
main.cpp
#include <string> #include <stack> #include <queue> using namespace std; #include "BaseCalc.h" char * express = "1+2*3-(4*5+6)/7-8/9"; bool IsNum(int a) { if (a>='1'&&a<='9') { return true; } return false; } double CalcPostFix(queue<CBaseCalc>& input_queue) { stack<CBaseCalc> stackTmp; do { CBaseCalc a = input_queue.front(); input_queue.pop(); if (a.GetType() != CalcType_Number) { printf("%c ", (int)a.GetValue()); CBaseCalc nNum1 = stackTmp.top(); stackTmp.pop(); CBaseCalc nNum2 = stackTmp.top(); stackTmp.pop(); double dRet = Calculate(a.GetType(), nNum2, nNum1); CBaseCalc nc(CalcType_Number); nc.SetValue(dRet); stackTmp.push(nc); } else { printf("%f ", a.GetValue()); //NumCalc nc; //nc.SetValue(a.GetValue()); stackTmp.push(a); } } while (!input_queue.empty()); return stackTmp.top().GetValue(); } void Fun() { queue<CBaseCalc> queuePostFix; stack<CBaseCalc> stackOpr; char* pCur = express; int nLen = strlen(express); int nCur = 0; int nLast = 0; string aNum; char cLast = 0; while (nCur <= nLen) { pCur = express + nCur++; if (IsNum(*pCur)) { aNum += *pCur; } else { if (!aNum.empty()) { CBaseCalc bc(CalcType_Number); int nValue = atoi(aNum.c_str()); bc.SetValue(nValue); queuePostFix.push(bc); aNum = ""; } if (stackOpr.empty()) { stackOpr.push(*pCur); } else { char cOpr = *pCur; cLast = cOpr; if ('(' == cOpr) { stackOpr.push(cOpr); } else if (')' == cOpr) { do { CBaseCalc a = stackOpr.top(); stackOpr.pop(); if (a.GetType() != CalcType_Operator_Left_Parenthesis) { queuePostFix.push(a); } else { break; } } while (true); } else { while (true) { CBaseCalc a = stackOpr.top(); if (a.GetType() == CalcType_Operator_Left_Parenthesis) { stackOpr.push(cOpr); break; } CBaseCalc b(cOpr); if (a<b) { stackOpr.push(b); break; } else { queuePostFix.push(a); stackOpr.pop(); } if (stackOpr.empty()) { stackOpr.push(cOpr); break; } } } } } //nCur++; } printf("\n"); double dRet=CalcPostFix(queuePostFix); printf("\n%s = %f\n", express, dRet); } int _tmain(int argc, _TCHAR* argv[]) { Fun(); return 0; }
本著開源精神送給後來程式設計師,沒有深度測試難免小BUG,希望學習者也是取其精華,修改別人bug也是自己提高的過程嘛。