计算四则运算表达式
- github链接:
0、 运行效果
1、 前期准备
网上各种找资料,各种问同学。其实最重要的还是自己要能理解 (⊙ˍ⊙) 讲真。光是理解别人怎么写我就花了好久的时间 (。_。)
真心要理解透才能做得出来 (⊙ˍ⊙) 网上的方式跟题目要求的都不一样...别人都是转成前缀式或后缀式,把数字和符号存到一起...题目却要求把数字和符号分别存入栈,简直造孽...
2、 问题与解决
- 先说一句自认为十分重要的话“一口吃不成大胖子”,讲真。刚开始的时候又想弄好对负数的处理又想弄好对优先级的判断,反而哪一件事情都没有做成,还把自己弄的很烦躁。后来就一步一步解决: 对“-a”和负数处理 -> 无括号运算 -> 有括号运算
- 一步一步来还有一个好处就是debug的时候,对代码调试的范围就会小很多,debug的效率也会提高。
赤裸裸的血的教训...真的很重要啊...
<1> 重复利用stringstream对象要记得.clear()
刚开始用的时候没有.clear(),发现怎么算都不对 0 0 回头把存符号和存数字的栈分别输出发现都是同一个符号或数字...翻翻资料发现要.clear()
<2> 对负号的处理
- 最开始想的是判断是否
- 前面是字符&&后面是数字
,如果是的话就把数字取负,-
换为+
再入栈。 - 后来发现会有
(-(1+3)*2+1)
这样的情况,虽然规定一下输入格式,改写成(1-(1+3)*2)
就可以没有问题了,但是这样计算器感觉用起来就不是那么方便了。 通过学霸指导,我就把对负号的处理改为在
-
前面补0。原先有想就在Calculation类
里面操作的,但是感觉不好判断-
号前面是否是负号..然后我就跑去上次写的scan类
里面在字符串存入queue
的时候直接补0,感觉这样会比较好操作一点。改完之后的试着输出一下,符合!!
<3> 计算表达式的值
- 感觉用栈的话适合用前缀式进行计算比较方便,不过不知道我怎么查的...查到的基本上都是用后缀式进行计算的...等我后缀式理解的七七八八了才发现有前缀式 (⊙ˍ⊙)
- 然后我应该用了不算后缀式的后缀式吧..
正宗后缀式:
我是再开了两个栈分别用来暂时存储符号和数据,大概想法(类似后缀式计算)如下(=o=)
其实
+ - * /
调试好之后,对括号的处理会方便很多,要考虑的情况也不算多,胜利的曙光就在眼前...<4> 对栈的调用
- 其实用法没什么难点,就是一定要注意你在调用
.top()
和.pop()
的时候stack是否为空
!!!!!!! 这点真的相当重要啊!!!无数次挂在这上面...写完一定要认真考虑每一次调用
.top()
或.pop()
的时候stack是否为空
!!!每一次!!!<5> 心态
- 在ddl还没延期之前,其实挺烦躁的...一大堆事情等着去做,眼看着ddl马上就要到了这次作业却还是不怎么会做,代码到处都是bug。
- 在此要感谢浩晖大神对我的...谆谆教诲?好吧,我不知道用什么词来形容 (゚ー゚)
- ddl截止的倒数第二天晚上吧,那时候感觉基本思路貌似已经成型了,但具体又不知道怎么下手,超级烦躁。去问浩晖大神也还是不是很懂,然后就负气的说了一句算了不看了也来不及了,之后就滚去睡觉了。第二天早上起来发现皓辉大神发了一大段话,大概意思就是 有没有做出题目本身并不重要,题目太难可以降低难度一步步实施,不要轻易放弃
- 看完之后就满血复活了hhh 而且说来也奇怪,第二天我就都做出来了 (>▽<)
再一次感谢浩晖大神对我的鼓励!!!
3、 待改进
- 目前写的代码都是默认输入的表达式完全合法,一旦表达式不合法就会有各种问题了 0 0
- 还有计算结果的处理。没办法像真正计算器那样限定总数字长度,有几位小数就输出几位小数。只能做到限制小数点后几位,如果小数点后没有小数位或不足限定位数时会补0。看起来总觉得是四舍五入后的结果...
4、 代码
自己试了些小数据暂且没有问题。
2016/04/13 更新
- 今天发现了一个八阿哥 (。_。)
- 测试数据:
-10000+20-(-(-20+2)*3-1/(2+6*3)-8)+2
- 不得不说那些被注释掉的代码挽救了我一命!!没花很久的时间就发现了bug ︿( ̄︶ ̄)︿
- 每次移动符号和数字的时候都要判断一下符号是否为
)
之前测的数据都比较巧合 0 0 刚好左括号后面都不是没有括号的计算..好像也不是这么说...原数据如果改成-10000+20-(-(-20+2)*3-1/(2+6*3)-8)
,在代码没有修改的情况下是可以运行的 0 0 - 运行效果
- 不过小数点后面的竟然被四舍五入了...更:
cout
改printf
就可以了 0 0 - 以下代码已更新
Calculation.h
#pragma once#include
#include #include #include using namespace std;class Calculation {public: //计算表达式的值 void ToCalculate(queue q);private: double m_dTemp; char m_cTemp; //存储数字 stack figure; stack figure_temp; //存储符号 stack operate; stack operate_temp;}; Calculation.cpp
#include
#include #include #include #include #include "Calculation.h"using namespace std;void Calculation::ToCalculate(queue q){ int operate_priority(char c); double calculate(char oper, double front, double behind); double _figure; stringstream stream; string m_strQue; //数字符号分别入stack while (!q.empty()) { m_strQue = q.front(); if (m_strQue[0] < '0' || m_strQue[0] > '9') { stream << m_strQue; stream >> m_cTemp; operate.push(m_cTemp); stream.clear(); } else { stream << m_strQue; stream >> m_dTemp; figure.push(m_dTemp); stream.clear(); } q.pop(); } /* while (!operate.empty()) { cout << operate.top() << endl; operate.pop(); } cout << "**************" << endl; while (!figure.empty()) { cout << figure.top() << endl; figure.pop(); } */ while (!operate.empty()) { //遇到左括号 if (operate.top() == ')') { operate_temp.push(operate.top()); operate.pop(); } else { if (operate_temp.empty()) { operate_temp.push(operate.top()); figure_temp.push(figure.top()); operate.pop(); figure.pop(); //operate可能为空 if (operate.empty()) { break; } } //运算符优先级比较计算 if ((operate_priority(operate.top()) < operate_priority(operate_temp.top())) && (operate_temp.top() != ')')) { //除数为0 if (operate_temp.top() == '/'&&figure_temp.top() == 0) { exit(0); } _figure = calculate(operate_temp.top(), figure.top(), figure_temp.top()); operate_temp.pop(); figure.pop(); figure_temp.pop(); figure.push(_figure); } else { //遇到左括号 if (operate.top() == ')') { operate_temp.push(operate.top()); operate.pop(); } else { operate_temp.push(operate.top()); figure_temp.push(figure.top()); operate.pop(); figure.pop(); } } //括号匹配 if (!operate.empty() && !operate_temp.empty() && (operate.top() == '('&&operate_temp.top() == ')')) { operate.pop(); operate_temp.pop(); } } /* cout << "operate" << endl; if (!operate.empty()) { cout << operate.top() << " "; } cout << endl; cout << "operate_temp" << endl; if (!operate_temp.empty()) { cout << operate_temp.top() << " "; } cout << endl; cout << "figure" << endl; if (!figure.empty()) { cout << figure.top() << " "; } cout << endl; cout << "figure_temp" << endl; if (!figure_temp.empty()) { cout << figure_temp.top() << " "; } cout << endl; cout << "****************************" << endl; */ } /* cout << "operate" << endl; while (!operate.empty()) { cout << operate.top() << " "; operate.pop(); } cout << endl; cout << "operate_temp" << endl; while (!operate_temp.empty()) { cout << operate_temp.top() << " "; operate_temp.pop(); } cout << endl; cout << "figure" << endl; while (!figure.empty()) { cout << figure.top() << " "; figure.pop(); } cout << endl; cout << "figure_temp" << endl; while (!figure_temp.empty()) { cout << figure_temp.top() << " "; figure_temp.pop(); } cout << endl; cout << "--------------------------" << endl; */ while (!operate_temp.empty()) { //除数为0 if (operate_temp.top() == '/'&&figure_temp.top() == 0) { exit(0); } _figure = calculate(operate_temp.top(), figure.top(), figure_temp.top()); operate_temp.pop(); figure.pop(); figure_temp.pop(); figure.push(_figure); } cout << figure.top() << endl;}//判断符号优先级int operate_priority(char c){ int pri; switch (c) { case '+': case '-': pri = 0; break; case '*': case '/': pri = 1; break; case '(': pri = -1; break; case ')': pri = 2; break; } return pri;}//计算double calculate(char oper, double front, double behind) { double result; switch(oper) { case '+': result = front + behind; break; case '-': result = front - behind; break; case '*': result = front * behind; break; case '/': result = front / behind; break; } return result;} 虽然阅读体验可能不太好,但是那些被注释掉的代码都是我流过的血和泪...实在舍不得删除...
5、 参考资料
- stringstream用法:
- stack用法:
- 带括号四则运算:
- 以上是我找的所有资料中参考度比较高的 0 0