计算器主要用到的知识比较简单,中缀表达式和后缀表达式,后缀表达式求值,以及栈这种数据结构,图形界面主要只用到了Qt的push button和label,计算器支持了两位数以上,小数和负数。
效果图:
源码:https://github.com/g1050/Calculator/tree/master
一、设计思路
二、什么是中缀和后缀表达式?
中缀表达式:9+(3-1)*3+10/2,这就是一个中缀表达式,顾名思义就是符号在中间的表达式,这是符合我们平时书写规范的表达式。但是对于计算机计算这种表达式就有点困难了,因为中间涉及括号和运算符号的优先级问题,因为如果计算机从左向右扫一遍的话不知道先计算哪些值,哪个和哪个值应该做何种运算,所以我们思考能不能先预处理一遍表达式,从而知道哪些值应该优先运算,所以后缀表达式应运而生。
后缀表达式:9 3 1 - 3 + 10 2 / + ,这是上式的后缀表达式。观察发现后缀表达式没有小括号,所以就解决了括号的问题,而运算符的优先级问题是通过栈这么一种结构来实现的。先不考虑是怎么转化过来的,我们先体会一下后缀表达式是怎么求值的,规则是这样的:从左到右扫描,1.如果是数字就进栈 2.如果是符号就弹出弹出栈顶两个元素(需要注意-和/要考虑两个操作符的顺序),运算后将结果在压入栈中。
以上就是后缀表达式求值的过程,下面看一下中缀怎么转为后缀表达式。
三、中缀转为后缀表达式
规则:
数字直接输出
符号----优先级+(1) -(1) *(2) /(2) ‘(’(0)
括号里表示优先级
优先级>栈顶就压栈,否则弹栈
左右括号特判
我们来举个例子:
需要注意的是最下面蓝色输出结果中,第一次输出的+是中缀表达式里面9后面的+,随后又将3后面的+入栈。
四、优点
这样先转后缀再对后缀求值的优点:
1.后缀表达式求值规则比较简单,中缀也不是不可以直接求值,两个栈一个操作数栈一个操作符栈,也可以解决,但是觉得后缀比较简单。
2.后缀表达式解决了括号和符号优先级问题。
3.中缀转后缀也不是很复杂。
五、多位数
目前程序存在的一个问题就是,多位数解析会出问题,比如:
9+(3-1)*3+10/2转后缀是9 3 1 - 3 + 10 2 / +,我们没办法区分是10十2二还是102一百零二,我的做法是每个数字解析后加一个#,所以结果就是这样的,9#3# 1# - 3# + 10# 2# / +
,这样每个完整数字后必跟一个#解决了解析出现多位数字粘在一起的情况。
六、负数
通过观察发现负数只有两种情况(可能考虑不周,还有遗漏的),一种类似-5+4…这种直接在首位是符号,另外一种是5+(-4)这样带括号的,我的处理方式是通过补一个0将单目负号变成双目减号,0-5+4… 和 5+(0-4),这样就和之前的处理一样了,应该还有更好的处理方式,欢迎补充!
七、小数
9+(3-1)3.141+10/2,小数问题也不难解决,比如这个3.141我们只要解析时判断数字后面是否接一个小数点,如果有,就把小数点后面按照3+110^(-1)+410 ^(-2)+110 ^(-3)这样解析就可以了,代码体现如下:
double cal::getValue()
{
int size = v.size();
stack <double> st;