概述:上篇我主要介绍了用QT做计算器的整个流程,这次主要就是分析一下,计算器表达式计算的算法部分。因为也找了很多别人写的代码,但大多都是只支持个位数的加减乘除,小数也不支持,所以就在原有框架上,修改,优化,让其满足我想要的功能。
1,表达式计算思路。
表达式数据操作符分割–>转为逆波兰表达式–>计算逆波兰表达式值–>输出结果。
2,表达式计算详解。
(1)表达式数据操作符分割
首先我们得到了一个字符串表达式,我们将数据和操作符分割。
如:表达式—————> “23+1.23-(2-5)*3”
分割后为“23” “+” “1.23” “- ”“( ”“2”“ -” “5” “)”“*” “3”,然后将其存入一个QString数组,这样数据,操作符分割就便于后面计算,辨别是数据还是操作符了。遍历数组,只要第一个字符不是0-9就是操作符了。
下面是这部分代码详解:
/*将表达式的数据,操作符分割,依次存入mask_buffer数组中*/
int Calculator::mask_data(QString expression, QString *mask_buffer)
{
int i,k = 0,cnt = 0;
QString::iterator p = expression.begin();//获取表达式头指针
int length = expression.length();//获取表达式数据长度
/*for 循环遍历整个表达式,进行数据,操作符分割*/
for(i = 0 ; i < length ; i += cnt,k++)
{
cnt = 0;
if(*p >= '0' && *p <= '9')
{
/*当第一个字符为0-9时,肯定是数字*/
QString temp = *p;
p ++;
cnt ++;
/*看数字后面是否还是数字或小数点,直到遇到下个操作符,这个数据才结束*/
while((*p >= '0' && *p <= '9') || *p == '.')
{
temp += *p;
p++;
cnt ++;
}
mask_buffer[k] = temp;
}else{
/*不是数字,就是操作符,直接写入数组即可*/
QString temp = *p;
p++;
cnt ++;
mask_buffer[k] = temp;
}
}
return k;
}
(2)转为逆波兰表达式。
既然用到逆波兰表达式,首先了解一下什么是逆波兰表达式。我们正常的表达式是中缀表达式,逆波兰就是将中缀表达式转化为后缀表达式。我们就简单粗暴一些,例子。
1+2*3-(2+5)———>中缀表达式。
1,2,3,*,+,2,5,+,- ———>后缀表达式。
中缀到后缀如何转化呢,下面就是详细的规则了:
首先我们定义一个数组A,堆栈B。数组A用于存储最后的后缀表达式,堆栈B就是一个过渡器,帮助我们转化,再定义操作符的优先级,如+ - * / ( )。
从左到右遍历整个表达式。
1,遇到数字加入数组A。
2,遇到左括号直接入栈到B。
3,遇到右括号,堆栈B出栈,加入到数组A中,直到遇到左括号,将左括号出栈但不加入数组A中。
4,如果遇到的是运算符:
(1)当堆栈B为空,直接入栈到B。
(2)当堆栈不为空,当前运算符优先级大于堆顶运算符优先级,入栈到B。
(3)当堆栈不为空,当前运算符优先级小于等于堆顶运算符优先级,B出栈到A数组中,直到堆顶运算符优先级小于当前运算符优先级,再将当前运算符入栈B。
5,当遍历完整个表达式,堆栈B不为空,依次出栈加入到A数组中。
下面详细步骤转