当前位置: 首页 > news >正文

数据结构(3.8)——栈的应用

栈在括号匹配中的应用

流程图

代码

#include <stdio.h>
#include <stdlib.h>
#define MaxSize 10typedef struct {char data[MaxSize];int top;
} SqStack;// 初始化栈
void InitStack(SqStack* S) {S->top = -1; // 初始化栈顶指针
}// 判空
bool StackEmpty(SqStack* S) {if (S->top == -1) {return true;} else {return false;}
}// 入栈
bool Push(SqStack* S, char x) {if (S->top == MaxSize - 1) { // 栈满,报错return false;} else {S->top = S->top + 1; // 指针先加1S->data[S->top] = x; // 新元素入栈return true;}
}// 出栈
bool Pop(SqStack* S, char* x) {if (StackEmpty(S)) {return false;} else {*x = S->data[S->top]; // 栈顶元素先出栈S->top = S->top - 1; // 指针减1return true;}
}// 括号匹配检查
bool bracketCheck(char str[], int length) {SqStack S;InitStack(&S); // 初始化一个栈for (int i = 0; i < length; i++) {if (str[i] == '(' || str[i] == '[' || str[i] == '{') {Push(&S, str[i]); // 扫描到左括号,入栈} else {if (StackEmpty(&S)) { // 扫描到右括号,且当前栈空return false; // 匹配失败}char topElem;Pop(&S, &topElem); // 栈顶元素出栈if (str[i] == ')' && topElem != '(') {return false;}if (str[i] == ']' && topElem != '[') {return false;}if (str[i] == '}' && topElem != '{') {return false;}}}return StackEmpty(&S); // 检索全部括号后,栈空说明匹配成功
}int main() {char str[] = "{([()])}";int length = sizeof(str) / sizeof(str[0]) - 1; // 计算字符串长度,减1是为了去掉结尾的'\0'if (bracketCheck(str, length)) {printf("括号匹配成功\n");} else {printf("括号匹配失败\n");}return 0;
}

栈在表达式求值中的应用

中缀、后缀、前缀表达式

中缀表达式

运算符在两个操作数中间:

  1. a + b
  2. a + b - c
  3. a + b - c * d

后缀表达式

运算符在两个操作数后面:

  1. ab +
  2. ab + c-或者a bc - +
  3. ab + cd * -

前缀表达式

运算符在两个操作数前面:

  1. + ab
  2. - + ab c
  3. - + ab * cd

中缀表达式转后缀表达式(手算)

  1. 确定中缀表达式中各个运算符的运算顺序
  2. 选择下一个运算符,按照[左操作数 右操作数 运算符]的方式组合成一个新的操作数(若运算顺序不唯一,则后缀表达式也不唯一)
  3. 如果还有运算符没被处理,就继续2步骤

例:

转换成后缀表式:          15 7 11+ - / 3 *  2 11 + + -

"左优先"原则:只要左边的运算符能先计算,就优先计算左边的(可保证运算唯一)

中缀表达式转后缀表达式(机算)

代码示例:

要将中缀表达式转换为后缀表达式,可以按照以下步骤进行:

  1. 初始化一个空栈,用于保存暂时还不能确定运算顺序的运算符。
  2. 初始化一个空字符串,用于保存最终的后缀表达式。
  3. 从左到右扫描中缀表达式中的每个字符。
  4. 对于每个字符,执行以下操作:
    • 如果是操作数,直接添加到后缀表达式中。
    • 如果是左括号 (,将其压入栈中。
    • 如果是右括号 ),则弹出栈中的运算符并添加到后缀表达式中,直到遇到对应的左括号 (。左括号 ( 弹出但不添加到后缀表达式中。
    • 如果是运算符(如 +-*/ 等),则将栈中所有优先级高于或等于当前运算符的运算符弹出并添加到后缀表达式中。然后将当前运算符压入栈中。
  5. 扫描完中缀表达式后,将栈中剩余的运算符全部弹出并添加到后缀表达式中。

下面是一个C语言的示例代码,用于将中缀表达式转换为后缀表达式:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX_SIZE 100// 栈的结构定义
typedef struct {char items[MAX_SIZE];int top;
} Stack;// 初始化栈
void initStack(Stack* stack) {stack->top = -1;
}// 判断栈是否为空
int isEmpty(Stack* stack) {return stack->top == -1;
}// 判断栈是否满
int isFull(Stack* stack) {return stack->top == MAX_SIZE - 1;
}// 压栈
void push(Stack* stack, char value) {if (isFull(stack)) {printf("Error: Stack is full.\n");return;}stack->items[++stack->top] = value;
}// 出栈
char pop(Stack* stack) {if (isEmpty(stack)) {printf("Error: Stack is empty.\n");return '\0';}return stack->items[stack->top--];
}// 获取栈顶元素
char peek(Stack* stack) {if (isEmpty(stack)) {printf("Error: Stack is empty.\n");return '\0';}return stack->items[stack->top];
}// 操作符优先级
int precedence(char op) {if (op == '+' || op == '-') {return 1;} else if (op == '*' || op == '/') {return 2;} else if (op == '(' || op == ')') {return 0;}return -1;
}// 中缀转后缀
void infixToPostfix(char* infix, char* postfix) {Stack stack;initStack(&stack);int i, j;for (i = 0, j = 0; infix[i] != '\0'; ++i) {if (infix[i] == ' ') continue;else if (isdigit(infix[i]) || isalpha(infix[i])) {postfix[j++] = infix[i];} else if (infix[i] == '(') {push(&stack, infix[i]);} else if (infix[i] == ')') {while (!isEmpty(&stack) && peek(&stack) != '(') {postfix[j++] = pop(&stack);}pop(&stack); // 弹出左括号} else {while (!isEmpty(&stack) && precedence(infix[i]) <= precedence(peek(&stack))) {postfix[j++] = pop(&stack);}push(&stack, infix[i]);}}while (!isEmpty(&stack)) {postfix[j++] = pop(&stack);}postfix[j] = '\0'; // 结束字符串
}int main() {char infix[] = "a+b*(c-d)-e/f";char postfix[MAX_SIZE];infixToPostfix(infix, postfix);printf("Infix: %s\n", infix);printf("Postfix: %s\n", postfix);return 0;
}
 

后缀表达式的计算(手算)

从左往右扫描,每遇到一个运算符,就让运算符前面最近的两个操作数执行对应运算,合体为一个操作数

注意:两个操作数的左右顺序

后缀表达式的计算(机算)

用栈实现后缀表达式的计算:

  1. 从左往右扫描下一个元素,直到处理完所以元素
  2. 若扫描到操作数则压入栈,并回到1;否则执行3
  3. 若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶,回到1

注意:后缀表达式先弹出的元素是‘右操作数’

入栈流程:

 中缀表达式转前缀表达式(手算)

  1. 确定中缀表达式中各个运算符的运算顺序
  2. 确定下一个运算符,按照[运算符 左操作数 右操作数]的方式组合成一个新的操作数
  3. 如果还有运算符没被处理,就继续2

"右优先"原则:只要右边的运算符能先计算,就优先算右边

前缀表达式的计算

  1. 从右往左扫描下一个元素,直到处理完所有元素
  2. 若扫描到操作数则压入栈,并回到1;否则执行3
  3. 若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结构压回栈顶,回到1

注意前缀表达式先弹出的元素是‘左操作数’

栈在递归中的应用

递归调用时,函数调用栈可称为“递归工作栈”

每进入一层递归,就将递归调用所需信息压入栈顶

每退出一层递归,就从栈顶弹出相应信息

  • 缺点:太多层递归可能会导致栈溢出

递归算法可能会包含很多重复计算 

总结

http://www.lryc.cn/news/396781.html

相关文章:

  • 前端面试题35(在iOS和Android平台上,实现WebSocket协议有哪些常见的库或框架?)
  • Mysql如何高效ALTER TABL
  • vue3+vite搭建第一个cesium项目详细步骤及环境配置(附源码)
  • LiteOS增加执行自定义源码
  • 《Nature》文章:ChatGPT帮助我学术写作的三种方式
  • 防火墙安全策略与用户认证综合实验
  • vue学习day05-watch侦听器(监视器)、Vue生命周期和生命周期的四个阶段、、工程化开发和脚手架Vue cli
  • 数字人+展厅互动体验方案:多元化互动方式,拓宽文化文娱新体验
  • 在Spring Boot项目中集成监控与报警
  • opencv实现目标检测功能----20240704
  • 音视频解封装demo:使用libmp4v2解封装(demux)出mp4文件中的h264视频数据和aac语音数据
  • 手撸俄罗斯方块(一)——简单介绍
  • 构建LangChain应用程序的示例代码:61、如何使用 LangChain 和 LangSmith 优化链
  • Android系统通过属性设置来控制log输出的方案
  • JavaDoc的最佳实践
  • 数字力量助西部职教全面提升——唯众品牌大数据、人工智能系列产品中标甘肃庆阳职院数字经济人才培养基地!
  • Swagger的原理及应用详解(四)
  • Elasticsearch7.10集群搭建
  • SMU Summer 2024 Contest Round 3
  • uniapp 封装瀑布流组件
  • pd虚拟机去虚拟化是什么意思?pd虚拟机去虚拟化教程 PD虚拟机优化设置
  • 低代码研发项目管理流程优化:提效与创新的双重驱动
  • 32位版 C 库函数time 将在 2038 年溢出,那到时候,它该何去何从
  • C语言 printf函数缓冲机制
  • 【Linux进阶】文件系统8——硬链接和符号连接:ln
  • 代码随想录算法训练营Day64|拓扑排序(卡码网117)、dijkstra朴素版
  • neo4j 图数据库:Cypher 查询语言、医学知识图谱
  • 数据结构基础--------【二叉树基础】
  • 数据开源 | Magic Data大模型高质量十万轮对话数据集
  • webpack之ts打包