中缀表达式到后缀表达式的转换是堆栈应用的典型例子。通过只允许操作‘+’,‘-’,‘*’,‘/’,并坚持优先级法则,即可实现该操作。
1. 规则
假设读入的中缀表达式是正确的。
当读到操作数时,立即输出。
操作符不立即输出,而是放入栈中。定义‘(’的优先级最高,其余符号同四则运算的法则。读入一个操作符时,弹出栈顶元素直至发现优先级更低的元素为止。除非是在处理一个‘)’,否则绝不从栈中弹出‘(’。遇到‘)’,将栈顶元素弹出并输出直到遇到相应的‘(’,但该‘(’只弹出,不输出。
读入输入的末尾时,若栈非空,依此弹出并输出所有栈元素。
2. 实例
以中缀表达式1+(2 -3 )*4+5 / 6 为例:
首先读入1,并输出。接着读入‘+’,此时栈为空,将‘+’压入栈中
这时读入‘(’,由于栈顶元素‘+’比‘(’的优先级低,故没有输出,‘(’进栈。接着,2被读入并输出。
接着‘-’读入,除非在处理‘)’,否则‘(’不会从栈中弹出。因此将‘-’压入栈中。下一个是3,被读入并输出。
此时读入‘)’,因此将栈元素直到‘(’弹出,输出一个‘-’。
接着读入‘’,栈顶元素‘+’优先级较低,故将乘号压入栈中。同时4被读入并输出。
继续进行,‘+’被读入,此时需要把‘’从栈弹出并输出;现在栈顶元素为‘+’,该算符不比刚刚遇到的‘+’优先级低而是具有相同的优先级,因而被弹出并放入输出中。然后,将谷歌遇到的‘+’压入栈中。同时5被读入并输出。
现在,读入‘/’,该算符优先级高于栈顶元素,因而被压入栈中。再往后读入6,并将其输出。
至此,输入为空,因而将栈元素全部弹出并输出,直至栈为空。
3. 代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define EmptyTOS -1 //栈空时指针指向
#define MinStackSize 5 //栈的最小容量
#define MaxArraySize 50 //待读取数组初始最大容量
typedef struct StackRecord* Stack;
struct StackRecord
{
int capacity; //栈容量
int TopOfStack; //栈顶
char* array;
};
Stack CreateStack(int size) //创建空栈
{
Stack s;
if (size < MinStackSize)
{
printf("The size is too small!\n");
return;
}
s = (Stack)malloc(sizeof(struct StackRecord));
s->capacity = size;
s->TopOfStack = EmptyTOS;
s->array = (char*)malloc(sizeof(char) * size);
return s;
}
int IsEmpty(Stack s)
{
return s->TopOfStack == EmptyTOS;
}
int IsFull(Stack s)
{
return s->TopOfStack == s->capacity - 1;
}
void Push(Stack s, char c) //压栈
{
if (IsFull(s))
{
printf("Error: the Stack is full!");
return;
}
else
{
s->array[++(s->TopOfStack)] = c;
}
}
char Top(Stack s) //返回栈顶元素,不弹出
{
if (IsEmpty(s))
{
printf("Error: the Stack is empty!");
return;
}
else
return s->array[s->TopOfStack];
}
char Pop(Stack s) //弹出栈顶元素
{
if (IsEmpty(s))
{
printf("Error: the Stack is empty!");
return;
}
else
return s->array[s->TopOfStack--];
}
int IsHigherThan(char x, char y) //优先级定义,'('具有最高优先级,其余同四则运算
{
if ((x == '(') && ((y == '+') || (y == '-') || (y == '*') || (y == '/')))
return 1;
else if (((x == '*') || (x == '/')) && ((y == '+') || (y == '-')))
return 1;
else
return 0;
}
void InfixToPostfix(char* a) //中缀转后缀
{
Stack s = CreateStack(50);
int i = 0;
while (a[i]!='\0')
{
if ((a[i] >= '0' && a[i] <= '9') || (a[i] >= 'a' && a[i] <= 'z') || (a[i] >= 'A' && a[i] <= 'Z'))
printf("%c ", a[i]); //数字直接输出
else if (a[i] == ')')
{
while (Top(s) != '(')
printf("%c ", Pop(s)); //遇到右括号,弹出并输出栈顶元素直到遇到左括号(左括号不输出)
Pop(s);
}
else
{
if (IsEmpty(s)) //栈空则直接推入栈中
Push(s, a[i]);
else if (IsHigherThan(a[i], Top(s))) //优先级高则推入栈中
Push(s, a[i]);
else
{
while (!IsEmpty(s) && (!IsHigherThan(a[i], Top(s)))) //弹出栈顶元素直至遇到优先级更低的元素
{
if (Top(s) != '(') //只有遇到右括号才能将左括号弹出
printf("%c ", Pop(s));
else
break;
}
Push(s, a[i]);
}
}
i++;
}
while (!IsEmpty(s)) //输入读取完毕栈非空,则依此弹出所有栈元素
{
printf("%c ", Pop(s));
}
}
int main()
{
char str[MaxArraySize];
printf("Enter the infix:\n");
gets(str);
printf("The postfix:\n");
InfixToPostfix(str);
return 0;
}
4.测试