一.基本概念:
逆波兰式(Reverse Polish notation,RPN,或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后)。
将中缀表达式转化为后缀表达式的原因:
原因就在于这个简单是相对人类的思维结构来说的,对计算机而言中序表达式是非常复杂的结构。相对的,逆波兰式在计算机看来却是比较简单易懂的结构。因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。
二.算法思路:
首先设置一个操作符栈,临时存放操作符,再设置一个队列或数组,存放后缀式。 以#
作为运算开始和结束的标志。
-
1、从左到右扫描中缀式,若碰到操作数,则把操作数加入后缀式中。
-
2、如果碰到操作符,就将其优先级与操作符栈的栈顶操作符比较。
a. 若碰到左括号,则压入操作符栈
b. 若碰到右括号,则将操作符栈内的元素依次移入到后缀式中,直到左括号停止(括号中依然遵循c,d两条)。
c. 若操作符的优先级高于栈顶操作符,则压入操作符栈
d. 若操作符的优先级等于或低于栈顶操作符,则将栈顶操作符移入到后缀式中,接着与操作符栈的下一个操作符比较,直到操作符高于,再将操作符压入到操作符栈中 。
三.代码演示:
输入样例:
a+b-a*((c+d)/e-f)+g#
输出样例:
ab+acd+e/f-*-g+
#include <stdio.h>
#include <string.h>
int Compare(char str1) {
if (str1 == '#') {
return 0;
} else if (str1 == '+' || str1 == '-') {
return 1;
} else if (str1 == '*' || str1 == '/') {
return 2;
} else if (str1 == '(' || str1 == ')') {
return 0;
}
else {
return -1; //字母或者数字
}
}
int main (void) {
//结果栈
char endStack[100];
int endTop = -1;
//操作符栈
char symbolStack[100];
int symbolTop = -1;
char str[100];
scanf("%s", str);
int length = (int)strlen(str);
for (int i = 0; i < length; ) {
if (Compare(str[i]) == -1) { //是字母或者数字就把它压入结果栈中
endStack[++endTop] = str[i++];
} else if (str[i] == '(') { //遇到(直接压入操作符栈中
symbolStack[++symbolTop] = str[i++];
} else if (str[i] == ')') { //遇到)将操作符栈中的符号全部弹出压入结果栈中
while (Compare(symbolStack[symbolTop]) != 0) {
endStack[++endTop] = symbolStack[symbolTop--];
}
symbolTop--;
i++;
} else { //遇到操作符
if (symbolTop == -1 || Compare(symbolStack[symbolTop]) < Compare(str[i])) { //操作符栈为空或者字符串中的操作符优先级大于操作符栈顶操作符的优先级就将该操作符压入操作符栈中
symbolStack[++symbolTop] = str[i++];
} else { //若字符串中的操作符优先级小于或等于操作符栈顶操作符的优先级,就将操作符栈的栈顶元素弹出压入结果栈中,并且字符串中的位置不变,直到操作符栈为空或遇到高优先级的操作符
endStack[++endTop] = symbolStack[symbolTop--];
}
if (str[i] == '#') {
break;
}
}
}
for (int i = 0; i < endTop + 1; i++) {
printf("%c", endStack[i]);
}
return 0;
}