平常我们所用的标准四则运算表达式,如:1+((2+3)*4)-5,叫做中缀表达式,今天介绍一种不需要括号的后缀表达法,我们也把它称为逆波兰式(Reverse Polish Notation ,RPN)表示。后缀表示式为栈数据结构的一种应用。
- 中缀表达式: 1+((2+3)*4)-5
- 后缀表达式: 123+4*+5-
其中上面的中缀表达式和后缀表达式等价。
后缀表达式遵循以下规则
- 从左到右遍历中缀表达式的每一个数字和符号。
- 若是数字就输出,即成为后缀表达式的一部分。
- 如果是符号,则判断其与栈顶符号的优先级,是右括号或已有栈顶符号优先级(乘除优于加减)大于等于此符号则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
那么怎么将中缀表达式转化为后缀表达式呢?
1)创建一个堆栈
2)从左往右顺序获取中缀表达式
2.1)遇到数字,直接输出
2.2)运算符
a:遇到左括号 '(' 直接入栈
b:遇到右括号 '(',将堆栈中左括号之前的元素全部压出堆栈。(PS:同时左括号也压出堆栈,但是我们并不打印输出)
c:遇到乘号 'x' 或者除号 '/' 直接入栈,直到遇到比它优先级更低的运算符,并以此压出堆栈。
d:遇到加号 '+' 或者减号 '-' 。如果此时是空栈,那么直接压入堆栈,否则,需要将栈中优先级高的运算符号依次压出堆栈(这里需要注意的是,如果堆栈中除了比它优先级高的运算符之外还有同等优先级的运算符,也要依次压出堆栈)直到栈变为空或者遇到左括号为止。
e:最后,获取完毕,将剩余的运算符号依次压出堆栈。
代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<ctype.h>
#define MAX_SIZE 100
typedef int Elemtype;
typedef struct SNode{
Elemtype *base; //栈底指针
Elemtype *top; //栈顶指针
int StackSize;
}SNode, *Stack;
void InitStack(Stack S)
{
S->base = (Elemtype *)malloc(sizeof(Elemtype) * MAX_SIZE);
assert(S->base != NULL);
S->top = S->base;
S->StackSize = MAX_SIZE;
}
//每次push后保持当前栈顶元素为空
void Push(Stack S, Elemtype c){
if((S->top - S->base) >= S->StackSize){
S->base = (Elemtype *)realloc(S->base, S->StackSize + MAX_SIZE);
assert(S->base != NULL);
S->top = S->base + MAX_SIZE;
}
*S->top = c;
S->top++;
}
int Stacklength(Stack S){
return (S->top - S->base);
}
//Function: 栈顶指针指向下一位元素,并且由地址p返回被pop的元素具体大小
int Pop(Stack S, Elemtype *p){
if(Stacklength(S) == 0){
return 0;
}
S->top--;
*p = *S->top; //利用地址p返回当前的栈顶元素
return 1;
}
void Change(char *str, Stack S){
InitStack(S);
int i = 0;
Elemtype c;
while(str[i] != '\0'){
if(isdigit(str[i])){
printf("%c", str[i]);
}
else if(str[i] == '+' || str[i] == '-'){
if(!Stacklength(S)){
Push(S, str[i]);
}
else {
do {
Pop(S, &c);
if(c == '('){
Push(S, c);
}
else {
printf("%c", c);
}
} while(Stacklength(S) && c != '(');
Push(S, str[i]);
}
}
else if(str[i] == '('){
Push(S, str[i]);
}
else if(str[i] == ')'){
Pop(S, &c);
while(c != '('){
printf("%c", c);
Pop(S, &c);
}
}
else if(str[i] == '*' || str[i] =='/'){
Push(S, str[i]);
}
else{
printf("Print Error\n");
}
i++;
}
while(Stacklength(S)){
Pop(S, &c);
printf("%c", c);
}
}
int main(){
char str[105];
Stack S = (Stack)malloc(sizeof(SNode));
fgets(str, MAX_SIZE, stdin);
str[strlen(str) - 1] = '\0';
Change(str, S);
return 0;
}