使用 C 的 DSA - 解析表达式
像 2*(3*4) 这样的普通算术表达式更容易被人脑解析,但对于算法来说,解析这样的表达式会相当困难。为了缓解这种困难,可以使用两步方法通过算法解析算术表达式。
将提供的算术表达式转换为后缀表示法。
评估后缀表示法。
中缀表示法
普通算术表达式遵循中缀表示法,其中运算符位于操作数之间。例如 A+B 此处 A 是第一个操作数,B 是第二个操作数,+ 是作用于两个操作数的运算符。
后缀表示法
后缀表示法与普通算术表达式或中缀表示法不同,因为运算符位于操作数之后。例如,请考虑以下示例。
Sr. No. | 中缀表示法 | 后缀表示法 |
---|---|---|
1 | A+B | AB+ |
2 | (A+B)*C | AB+C* |
3 | A*(B+C) | ABC+* |
4 | A/B+C/D | AB/CD/+ |
5 | (A+B)*(C+D) | AB+CD+* |
6 | ((A+B)*C)-D | AB+C*D- |
中缀到后缀的转换
在研究如何将中缀转换为后缀表示法之前,我们需要考虑以下中缀表达式求值的基本知识。
中缀表达式的求值从左到右开始。
记住优先级,例如 * 的优先级高于 +。例如
2+3*4 = 2+12.
2+3*4 = 14.
-
使用括号覆盖优先级,例如
(2+3)*4 = 5*4.
(2+3)*4= 20.
现在让我们手动将简单的中缀表达式 A+B*C 转换为后缀表达式。
Sr.No | Character读 | 中缀表达式解析至此 | 后缀表达式开发至此 | 备注 |
---|---|---|---|---|
1 | A | A | A | |
2 | + | A+ | A | |
3 | B | A+B | AB | |
4 | * | A+B* | AB | + 无法复制,因为 * 具有更高的优先级。 |
5 | C | A+B*C | ABC | |
6 | A+B*C | ABC* | 复制 *,因为有两个操作数 B 和 C | |
7 | A+B*C | ABC*+ | 复制 +,因为有两个操作数 BC 和 A |
现在让我们使用堆栈将上面的中缀表达式 A+B*C 转换为后缀表达式。
Sr.No | 读取的字符 | 到目前为止解析的中缀表达 | 到目前为止开发的后缀表达式 | 堆栈内容 | 备注 |
---|---|---|---|---|---|
1 | A | A | A | ||
2 | + | A+ | A | + | 将 + 运算符推送到堆栈中。 |
3 | B | A+B | AB | + | |
4 | * | A+B* | AB | +* | 运算符 * 的优先级高于 +。将 * 运算符推送到堆栈中。否则,+ 会弹出。 |
5 | C | A+B*C | ABC | +* | |
6 | A+B*C | ABC* | + | 没有更多操作数,弹出 * 运算符。 | |
7 | A+B*C | ABC*+ | 弹出 + 运算符。 |
现在让我们看另一个示例,通过使用堆栈将中缀表达式 A*(B+C) 转换为后缀表达式。
Sr.No | 读取的字符 | 到目前为止解析的中缀表达 | 到目前为止开发的后缀表达式 | 堆栈内容 | 备注 |
---|---|---|---|---|---|
1 | A | A | A | ||
2 | * | A* | A | * | 将 * 运算符推送到堆栈中。 |
3 | ( | A*( | A | *( | 将 ( 推送到堆栈中。 |
4 | B | A*(B | AB | *( | |
5 | + | A*(B+ | AB | *(+ | 将 + 压入堆栈。 |
6 | C | A*(B+C | ABC | *(+ | |
7 | ) | A*(B+C) | ABC+ | *( | 弹出 + 运算符。 |
8 | A*(B+C) | ABC+ | * | 弹出 ( 运算符。 | |
9 | A*(B+C) | ABC+* | 弹出其余运算符。 |
示例
现在我们将演示如何使用堆栈将中缀表达式转换为后缀表达式,然后计算后缀表达式。
#include<stdio.h> #include<string.h> //字符堆栈 char stack[25]; int top=-1; void push(char item) { stack[++top]=item; } char pop() { return stack[top--]; } //返回运算符的优先级 int precedence(char symbol) { switch(symbol) { case '+': case '-': return 2; break; case '*': case '/': return 3; break; case '^': return 4; break; case '(': case ')': case '#': return 1; break; } } //检查符号是否为运算符? int isOperator(char symbol) { switch(symbol){ case '+': case '-': case '*': case '/': case '^': case '(': case ')': return 1; break; default: return 0; } } //将中缀表达式转换为后缀表达式 void convert(char infix[],char postfix[]){ int i,symbol,j=0; stack[++top]='#'; for(i=0;i<strlen(infix);i++){ symbol=infix[i]; if(isOperator(symbol)==0){ postfix[j]=symbol; j++; } else { if(symbol=='('){ push(symbol); } else { if(symbol==')'){ while(stack[top]!='('){ postfix[j]=pop(); j++; } pop();//pop out (. } else { if(precedence(symbol)>precedence(stack[top])) { push(symbol); } else { while(precedence(symbol)<=precedence(stack[top])) { postfix[j]=pop(); j++; } push(symbol); } } } } } while(stack[top]!='#') { postfix[j]=pop(); j++; } postfix[j]='\0';//null terminate string. } //int stack int stack_int[25]; int top_int=-1; void push_int(int item) { stack_int[++top_int]=item; } char pop_int() { return stack_int[top_int--]; } //evaluates postfix expression int evaluate(char *postfix){ char ch; int i=0,operand1,operand2; while( (ch=postfix[i++]) != '\0') { if(isdigit(ch)){ push_int(ch-'0'); // Push the operand } else { //Operator,pop two operands operand2=pop_int(); operand1=pop_int(); switch(ch) { case '+': push_int(operand1+operand2); break; case '-': push_int(operand1-operand2); break; case '*': push_int(operand1*operand2); break; case '/': push_int(operand1/operand2); break; } } } return stack_int[top_int]; } void main() { char infix[25] = "1*(2+3)",postfix[25]; convert(infix,postfix); printf("Infix expression is: %s " , infix); printf("Postfix expression is: %s " , postfix); printf("Evaluated expression is: %d " , evaluate(postfix)); }
输出
如果我们编译并运行上述程序,则会产生以下输出 −
Infix expression is: 1*(2+3) Postfix expression is: 123+* Result is: 5