此程序是在学习Qt的时候写的,Qt入门简单,了解布局之后能迅速实现自己想要的界面,布局是比较简单的部分,不写。算法可能是多数人包括我自己比较薄弱的地方,因此在这里做主要介绍。 学过编译原理或者离散数学的话可能知道后缀表达式。后缀表达式是运算符写在操作数后边不包扩括号的算数表达式,也叫逆波兰表达式。中缀表达式对人来说很好理解,但是对于计算机来说就很困难,在中缀表达式的情况下求值,既要考虑括号,优先级,还要考虑操作符出现的先后顺序,但是后缀表达式就不同,后缀表达式的运算符是按照一定的顺序出现的,所以不不许要加括号来决定优先级的高低,一次遍历就可以完成计算,相比中缀表达式,算法的复杂度要降低很多。
中缀表达式->后缀表达式
转换方法:
- 1. 首先将这个中缀表达式的所有运算加括号 ((a+(b*c))-(d+e))
- 2. 然后将所有运算符放到相应括号的后面,变成了 ((a(bc)*)+(de)+)-
- 3. 最后把所有括号去掉,得到的结果就是后缀表达式:abc*+de+-
另一种方法:
- 将中缀表达式中的操作数看成叶子节点,将所有的操作符表示成内节点,画出该二叉树。
- 对该二叉树按照前序|中序|后序的遍历方式遍历就可以得到相应的表达式。
编程实现方法:
利用堆栈来做临时的运算符存取场所:
例如:1+2*3-(4+5)*6 后缀表达式为:123*+45+6*-
现在用字符数组mid存储中缀表达式,用end存储后缀表达式,堆栈为mystack来模拟下过程:
序号 中缀表达式mid 堆栈操作 堆栈mystack 后缀表达式end
0 1+2*3-(4+5)*6 无 空 空
1 +2*3-(4+5)*6 无 空 1
2 2*3-(4+5)*6 push + 1
3 *3-(4+5)*6 无 + 12
4 3-(4+5)*6 push *+ 12
5 -(4+5)*6 无 *+ 123
6 (4+5)*6 <-pop <-pop push - 123*+
7 4+5)*6 push (- 123*+
8 +5)*6 无 (- 123*+4
9 5)*6 push +(- 123*+4
10 )*6 无 +(- 123*+45
11 *6 <-pop pop - 123*+45+
12 6 push *- 123*+45+
13 空 无 *- 123*+45+6
14 空 <-pop <-pop 空 123*+45+6*- // 扫描结束,将所有的操作符出栈
声明:<-pop表示弹出的数据存入end中,pop仅仅弹出数据不存人end.
函数原型:
//中缀表达式转为后缀表达式的实现
void calculator::mid2end(const char* mid,char* end){
int i=0;
int j=0;
while(mid[i]){
if(mid[i] == '.'||mid[i] == '%')continue;
//mystack.push('#');
//遇到数字直接存入end,
if(mid[i]>='0'&&mid[i]<='9'){
end[j++] = mid[i];
}else if(mid[i]=='-'||mid[i]=='+'){
//加号和减号的操作
if(!mystack.isEmpty()){
while((!mystack.isEmpty()) && (mystack.top()=='+'||mystack.top()=='-'||mystack.top()=='*'||mystack.top()=='/')){
//只要是优先级不小于+-的运算符
end[j++]=mystack.pop();
}
}
mystack.push(mid[i]);
}else if(mid[i]=='*'||mid[i]=='/'){
if(!mystack.isEmpty()){
while((!mystack.isEmpty()) && (mystack.top()=='*'||mystack.top()=='/')){
end[j++]=mystack.pop();
}
}
mystack.push(mid[i]);
}else if('('==mid[i]){
mystack.push(mid[i]);
}else if(')'==mid[i]){
//遇到)将(之前的所有数据输出之后将(出栈
if(!mystack.isEmpty()){
while((!mystack.isEmpty()) && mystack.top()!='('){
end[j++]=mystack.pop();
}
}//当前的)直接输出
mystack.pop();
}
i++;
}
//扫描结束将所有的操作符出栈
while(!mystack.isEmpty())end[j++]=mystack.pop();
}
同样利用堆栈计算后缀表达式的和:
int calculator::calculate(const char* end){
int i=0;
int a;
int b;
while(end[i])
{
switch(end[i]){
case '+':
b = mystack.pop();
a = mystack.pop();
mystack.push(a+b);
qDebug()<<a<<"+"<<b<<"="<<mystack.top()<<endl;
break;
case '-':
b = mystack.pop();
a = mystack.pop();
mystack.push(a-b);
qDebug()<<a<<"-"<<b<<"="<<mystack.top()<<endl;
break;
case '*':
b = mystack.pop();
a = mystack.pop();
mystack.push(a*b);
qDebug()<<a<<"*"<<b<<"="<<mystack.top()<<endl;
break;
case '/':
b = mystack.pop();
a = mystack.pop();
mystack.push(a/b);
qDebug()<<a<<"/"<<b<<"="<<mystack.top()<<endl;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
mystack.push(end[i]-'0');//ASCII码 ‘8’ - ‘0’ == 8;
}
i++;
}
return mystack.top();
}
界面:
源代码上传到我的空间 [表达式计算器],还有许多处不足,需要限制用户的操作。
若您有更好的关于表达式的计算方法请留言。