学习了栈的基本的操作后,我们可以做一个应用案例:中缀表达式转为后缀表达式。
人们所熟悉的表达式写法为中缀表达式,但是计算机喜欢后缀表达式,因为不用管理括号匹配的问题,可以利用栈直接计算。
如 :8 +( 3 – 1 ) * 5 => 8 3 1 – 5 * +
给你一个字符串str:8 +( 3 – 1 ) * 5,将它转化为后缀表达式吧。算法如下:
中缀转后缀算法:
遍历中缀表达式中的数字和符号:
- 对于数字:直接输出
- 对于符号:
- 左括号:进栈
- 运算符号:与栈顶符号进行优先级比较
- 若栈顶符号优先级低:此符号进栈 (默认栈顶若是左括号,左括号优先级最低)
- 若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
- 右括号:将栈顶符号弹出并输出,直到匹配左括号,将左括号和右括号同时舍弃
- 遍历结束:将栈中的所有符号弹出并输出
代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 1024
// 中缀表达式转后缀表达式案例
// 顺序栈
struct SStack {
void* data[MAX]; // 维护一个数组 每个元素类型void*
int m_Size; // 栈的大小
};
typedef void* SeqStack;
//初始化栈
SeqStack init_SeqStack() {
struct SStack* myStack = malloc(sizeof(struct SStack));
if (myStack == NULL) {
return NULL;
}
memset(myStack->data, 0, sizeof(void*) * MAX); // 数组清空
myStack->m_Size = 0;
return myStack;
}
// 入栈
void push_SeqStack(SeqStack stack, void* data) {
//入栈本质 数组尾插
if (stack == NULL) {
return;
}
if (data == NULL) {
return;
}
struct SStack* mystack = stack;
if (mystack->m_Size == MAX) {
return;
}
mystack->data[mystack->m_Size] = data;
mystack->m_Size++;
}
// 出栈
void pop_SeqStack(SeqStack stack) {
//出栈本质 尾删
if (stack == NULL) {
return;
}
struct SStack* mystack = stack;
if (mystack->m_Size == 0) {
return;
}
mystack->data[mystack->m_Size - 1] = NULL; //逻辑删除
mystack->m_Size--;
}
// 返回栈顶
void* top_SeqStack(SeqStack stack) {
if (stack == NULL) {
return NULL;
}
struct SStack* mystack = stack;
if (mystack->m_Size == 0) {
return NULL;
}
return mystack->data[mystack->m_Size - 1];
}
// 返回栈的大小
int size_SeqStack(SeqStack stack) {
if (stack == NULL) {
return -1;
}
struct SStack* mystack = stack;
return mystack->m_Size;
}
// 判断栈是否为空
int isEmpty_SeqStack(SeqStack stack) {
if (stack == NULL) {
return -1; //代表真--- 空栈
}
struct SStack* mystack = stack;
if (mystack->m_Size == 0) {
return 1;
}
return 0; // 代表不是空栈
}
// 销毁栈
void destroy_SeqStack(SeqStack stack) {
if (stack == NULL) {
return;
}
free(stack);
stack = NULL;
}
//判断是否为数字
int isNumber(char ch) {
if ('0' <= ch && ch <= '9') {
return 1;
}
else
return 0;
}
// 优先级确认函数
int priority(char ch) {
int pri = 0;
if (ch == '*' || ch == '/')
pri = 2;
if (ch == '+' || ch == '-')
pri = 1;
if (ch == '(')
pri = 0;
return pri;
}
int main() {
char* str = "8+(3-1)*5"; // 中缀表达式
char* p = str;
char dst[MAX] = { 0 };
int i = 0;
// 初始化栈
SeqStack mystack = init_SeqStack();
while (*p) {
// 先判断是否为数字
if (isNumber(*p)) {
dst[i] = *p;
i++;
}
// 如果为符号
else {
//如果是左括号
if (*p == '(') {
push_SeqStack(mystack, p);
}
else if (size_SeqStack(mystack) > 0) {
// 栈中有元素,需要进行优先级比较
// 分为两种情况:
// 右括号*****************************
if (*p == ')') {
//将栈顶元素弹出,直到匹配到左括号;并将左括号与右括号同时舍弃
while (*(char*)(top_SeqStack(mystack)) != '(') {
dst[i] = *(char*)(top_SeqStack(mystack));
pop_SeqStack(mystack);
i++;
}
// 遇到左括号 弹出
pop_SeqStack(mystack);
}
// 栈顶优先级符号高
else if (priority(*(char*)(top_SeqStack(mystack))) > priority(*p)) {
//将栈顶符号弹出 并输出 再入栈
dst[i] = *(char*)(top_SeqStack(mystack));
pop_SeqStack(mystack);
push_SeqStack(mystack, p);
i++;
}
else {
push_SeqStack(mystack, p);
}
}
else
// 不是数字的第一个字符 入栈
push_SeqStack(mystack, p);
}
p++;
}
// 遍历结束 将栈中所有符号弹出并输出
while (isEmpty_SeqStack(mystack) == 0) {
// 栈不为空
dst[i] = *(char*)(top_SeqStack(mystack));
pop_SeqStack(mystack);
i++;
}
// 打印字符串
printf("%s\n", dst);
// 销毁栈
destroy_SeqStack(mystack);
mystack = NULL;
system("pause");
return 0;
}
程序运行结果: