您的位置:首页 > 其它

中缀表达式与后缀表达式

2013-03-02 23:04 531 查看
[问题描述]:如何计算一个表达式的值?

表达式的表示形式有中缀、前缀和后缀三种形式。中缀表达式就是我们平时使用的表达式,按操作符的优先级进行计算:先乘除后加减,有括号先算括号里面的。中缀表达式便于人进行计算,但不便于计算机解析。后缀表达式没有优先级,计算规则简单,因此便于计算机进行解析。先将中缀表达式转换为后缀表达式,然后再计算。

后缀表达式的计算过程为:

从左到右依次扫描输入的后缀表达式,当遇到的是

操作数,直接压栈;
运算符,取两个操作数进行计算,并将计算结果压栈。
 

 将中缀表达式转化为后缀表达式的过程为:

从左到右依次扫描输入的中缀表达式,当遇到的是

操作数:直接输出;
开括号:压栈;
闭括号:
若栈为空,则括号不匹配,错误;
若栈不为空,将栈里的元素依次弹出,直至遇到第一个开括号;

运算符:
当栈顶不是开括号,且该运算符的优先级不高于栈顶元素的优先级,则不断将栈顶元素弹出并输出;
将该运算符压栈。

最后,如果栈非空,则将所有元素弹出并输出。

实现代码(没有进行语法检查和错误处理)如下。为了便于后缀表达式的计算,在输出的后缀表达式中插入了空白分隔字符。

#include <iostream>
#include <stack>
using namespace std;

#define MAXLEN 100

bool isDigit(char c){
return (c >= '0' && c <= '9') || (c == '.');
}

// 中缀转为后缀
void infix2postfix(char *infix, char *postfix){
// preprocess(infix);
int priority[128] = {0};
priority['+'] = priority['-'] = 1;
priority['*'] = priority['/'] = 2;

stack<char> Stack;
int i = 0, k = 0;
char c = 0;

for(i = 0; infix[i] != 0; i++){
switch (infix[i]){
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9': case '0':
case '.':
postfix[k++] = infix[i];
break;
case '(':
Stack.push('(');
break;
case ')':
if(isDigit(postfix[k-1]))
postfix[k++] = ' ';
while((c = Stack.top()) != '('){
postfix[k++] = c;
postfix[k++] = ' ';
Stack.pop();
}
Stack.pop();
break;
case '+':
case '-':
case '*':
case '/':
if(isDigit(postfix[k-1]))
postfix[k++] = ' ';
while(!Stack.empty() && Stack.top() != '(' &&
priority[c = Stack.top()] >= priority[infix[i]]){
postfix[k++] = c;
postfix[k++] = ' ';
Stack.pop();
}
Stack.push(infix[i]);
break;
case ' ': case '\t':
break;
default:
break;
}
}

while(!Stack.empty()){
postfix[k++] = ' ';
postfix[k++] = Stack.top();;
Stack.pop();
}

postfix[k] = 0;
}

// 计算后缀表达式
double calcPostfix(char *postfix){
stack<double> Stack;
double a, b;
int i = 0, k = 0;
char num[100];

enum InDigit{IN, OUT};
InDigit indigit = OUT;

for(i = 0; postfix[i]; i++){
if(isDigit(postfix[i])){
indigit = IN;
num[k++] = postfix[i];
}
else{
if(indigit == IN){
num[k] = 0;
k = 0;
Stack.push(atof(num));
}
indigit = OUT;

switch (postfix[i]){
case '+':
a = Stack.top(); Stack.pop();
b = Stack.top(); Stack.pop();
Stack.push(a + b);
break;
case '-':
a = Stack.top(); Stack.pop();
b = Stack.top(); Stack.pop();
Stack.push(b - a);
break;
case '*':
a = Stack.top(); Stack.pop();
b = Stack.top(); Stack.pop();
Stack.push(a * b);
break;
case '/':
a = Stack.top(); Stack.pop();
b = Stack.top(); Stack.pop();
Stack.push(b / a);
break;
default:
break;
}
}
}

if(indigit == IN){
num[k] = 0;
Stack.push(atof(num));
}

return Stack.top();
}

int main()
{
char infix[MAXLEN] = "1+( (1) + (1+1)*2+3 / 4 *2-10) / 2";
char postfix[MAXLEN] = {0};

infix2postfix(infix, postfix);

cout<<postfix<<endl;
cout<<calcPostfix(postfix)<<endl;
return 0;
}

需要注意的是,负号(-)比较特殊。与减号不同,负号是单目运算符,在转换之前需要对中缀表达式进行预处理。预处理也很容易,因此减号前面是操作数,而负号前面是一定括号或者边界,只需要在负号前面加0就可以了。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息