描述
人们熟悉的四则运算表达式称为中缀表达式,例如(23+34*45/(5+6+7))。在程序设计语言中,可以利用堆栈的方法把中缀表达式转换成保值的后缀表达式(又称逆波兰表示法),并最终变为计算机可以直接执行的指令,得到表达式的值。
给定一个中缀表达式,编写程序,利用堆栈的方法,计算表达式的值。
输入
第一行为测试数据的组数N
接下来的N行,每行是一个中缀表达式。表达式中只含数字、四则运算符和圆括号,操作数都是正整数,数和运算符、括号之间没有空格。中缀表达式的字符串长度不超过600。
输出
对每一组测试数据输出一行,为表达式的值
解法
该问题可以转换为两个子问题:
1、将中缀表达式转换为后缀表达式
2、利用栈对后缀表达式求值
中缀表达式转后缀表达式
算法: 可以使用栈来完成中缀表达式到后缀表达式的转换
1、栈stack[]用来存储操作符,top指向栈顶,但不存储元素,top=0表示栈为空
2、从左向右遍历中缀表达式
a.如果遇到的是操作数num,则直接输出到后缀表达式
b.如果遇到的是操作符op,则有几种情况:
b.1.如果op==')',则依次弹出栈顶直到弹出'(',但'('不输出到后缀表达式
b.2:如果op=='(',则直接入栈
b.3:如果栈为空,则直接入栈
b.4:如果op的优先级高于栈顶操作符的优先级,则入栈
b.5:如果op的优先级低于或等于栈顶操作符的优先级,则依次弹出栈顶直到op的优先级高于栈顶操作符的优先级(或栈为空),再将op入栈
3、遍历完时,如果栈仍不为空,则依次弹出栈顶直到栈为空
具体的代码如下:
1 int mycmp(char a, char b) { 2 if(b == '(') 3 return 1;//左括号直接入栈 4 else if((b == '*' || b == '/') &&(a == '+' || a == '-' || a == '(')) 5 return 1;//*、/优先级高于+、-、(,入栈 6 else if((b == '+' || b == '-') && (a == '(')) 7 return 1;//+、-优先级高于(,入栈 8 else 9 return 0; 10 } 11 12 /*中缀表达式转后缀表达式 13 中缀表达式之间无分割 14 后缀表达式操作数、操作符之间用空格分割,便于区分不同操作数*/ 15 void infix_to_suffix(char* infix, char* suffix) { 16 int i, k, j=0, top=0; 17 char stack[1000];//存储运算符的栈 18 19 for(i=0; infix[i]!='\0'; i++) { 20 if(infix[i] >= '0' && infix[i] <= '9') { 21 suffix[j++] = infix[i];//操作数则直接输出 22 } else { 23 if(i != 0 && infix[i-1] >= '0' && infix[i-1] <= '9') { 24 suffix[j++] = ' ';//操作数后补充空格分割 25 } 26 if(infix[i] == ')') { 27 //遇到右括号则一直弹出直到左括号,但左括号不输出 28 while(stack[top-1] != '(') { 29 suffix[j++] = stack[--top]; 30 suffix[j++] = ' '; 31 } 32 top--; 33 } else if(top == 0 || mycmp(stack[top-1], infix[i])) { 34 //栈为空或当前操作符的优先级高于栈顶操作符,当前操作符入栈 35 stack[top++] = infix[i]; 36 } else { 37 //当前操作符优先级等于或低于栈顶操作符则弹出栈顶 38 while(!mycmp(stack[top-1], infix[i])) { 39 suffix[j++] = stack[--top]; 40 suffix[j++] = ' '; 41 if(top == 0) 42 break; 43 } 44 stack[top++] = infix[i];//当前操作符入栈 45 } 46 } 47 } 48 //补充空格分割 49 if(suffix[j-1] != ' ') { 50 suffix[j++] = ' '; 51 } 52 //如果操作符栈不为空,弹出所有操作符 53 while(top != 0) { 54 suffix[j++] = stack[--top]; 55 suffix[j++] = ' '; 56 } 57 suffix[j] = '\0'; 58 }
利用栈对后缀表达式求值
算法:
1、栈stack[]用来存储操作数,top指向栈顶,但不存储元素,top=0表示栈为空,
2、从左向右依次遍历后缀表达式
a.如果遇到的是操作数num,则直接将num入栈,即stack[top++]=num
b.如果遇到的是操作符op,则取出依次取出栈顶的两个元素stack[top-2]和stack[top-1],计算stack[top-2] op stack[top-1]的结果,并将结果入栈
3、遍历结束时,stack[top-1]即为后缀表达式求值结果
具体的C语言代码如下:
1 /*后缀表达式求值*/ 2 int suffix_value(char* suffix) { 3 int i, j; 4 char op; 5 int stack[1000]; 6 int top = 0, value = 0; 7 for(i=0; suffix[i] != '\0'; i++) { 8 if(suffix[i] >= '0' && suffix[i] <= '9') { 9 value = value*10 + suffix[i] - '0'; 10 } else if(suffix[i] == ' ') { 11 //操作数入栈 12 stack[top++] = value; 13 value = 0; 14 } else { 15 //根据操作符,对栈顶两个操作数进行计算并得到结果 16 switch(suffix[i]) { 17 case '+': value = stack[top-2] + stack[top-1];break; 18 case '-': value = stack[top-2] - stack[top-1];break; 19 case '*': value = stack[top-2] * stack[top-1];break; 20 case '/': value = stack[top-2] / stack[top-1];break; 21 default: break; 22 } 23 top -= 2; 24 } 25 } 26 27 return stack[0]; 28 }
至此,中缀表达式求值的主程序如下:
1 int main() { 2 int n; 3 char infix[1000], suffix[1000];//infix中缀表达式,suffix后缀表达式 4 5 scanf("%d\n", &n); 6 while(n--) { 7 gets(infix); 8 infix_to_suffix(infix, suffix); 9 printf("%d\n", suffix_value(suffix)); 10 } 11 12 return 0; 13 }