栈和队列是数据结构中的两种基本线性结构,它们在计算机科学中有着广泛的应用。本文基于提供的文档内容,系统梳理栈在表达式求值、递归、括号匹配中的应用,以及队列在树、图和操作系统中的应用。回复结构丰富,包含标题、小节、列表和图片嵌入,以增强可读性。
一、栈的应用:表达式求值
表达式求值是栈的核心应用之一,主要涉及中缀、后缀和前缀表达式的转换与计算。
1. 三种算术表达式
-
中缀表达式 :运算符在两个操作数中间,如
A + B
,需使用界限符(如括号)明确运算顺序。 -
后缀表达式 (逆波兰表达式):运算符在两个操作数后面,如
A B +
,无歧义且易于机算。 -
前缀表达式 (波兰表达式):运算符在两个操作数前面,如
+ A B
。
2. 中缀表达式转后缀表达式
手算方法:
-
步骤:
-
确定中缀表达式中各运算符的运算顺序。
-
按「左操作数 右操作数 运算符」组合新操作数。
-
重复直到所有运算符处理完毕。
-
-
"左优先"原则:保证运算顺序唯一,避免自由风格导致结果不一致。
机算方法:
-
使用栈暂存运算符,算法流程:
-
初始化运算符栈。
-
扫描元素:
-
操作数:直接加入后缀表达式。
-
界限符:
(
入栈;)
弹出栈内运算符直到(
。 -
运算符:弹出优先级≥当前运算符的所有运算符,再入栈。
-
-
最后将栈中剩余运算符弹出。
-
3. 后缀表达式的计算
手算方法:
从左往右扫描,遇到运算符时,取最近两个操作数运算,合并为新操作数。注意操作数左右顺序。
机算方法:
-
用栈实现:
-
扫描元素,操作数入栈。
-
遇到运算符时,弹出两个栈顶元素(先右操作数,后左操作数),运算后结果压回栈。
-
最终栈中唯一元素即为结果。
示例:后缀式
A B + C D * E / - F +
的计算过程涉及多次栈操作。
-
4. 中缀表达式的计算(用栈实现)
结合中缀转后缀和后缀求值算法:
-
初始化操作数栈和运算符栈。
-
扫描中缀表达式:
-
操作数:压入操作数栈。
-
运算符/界限符:按中缀转后缀逻辑处理运算符栈,弹出运算符时同步从操作数栈弹出两个操作数运算,结果压回操作数栈。
-
-
优点:直接计算中缀表达式,避免显式转换。
二、栈的应用:递归
递归是栈的典型应用,通过函数调用栈实现。
1. 函数调用过程
-
函数调用时,栈存储:
-
调用返回地址
-
实参
-
局部变量
-
-
特点:最后被调用的函数最先结束(LIFO),递归工作栈每层递归压入/弹出信息。
2. 递归示例
-
阶乘计算:
factorial(n) = n * factorial(n-1)
(递归体),边界条件n=0
或n=1
时返回 1。递归深度较大时可能导致栈溢出。
-
斐波那契数列:
递归表达式包含重复计算,效率低。
3. 递归的优缺点
-
优点:简化代码,问题分解直观。
-
缺点:栈溢出风险、重复计算;可自定义栈改造成非递归算法。
三、栈的应用:括号匹配
括号匹配是栈的基础应用,确保表达式中的括号正确配对。
1. 算法原理
-
扫描字符:
-
左括号(
(
,[
,{
):入栈。 -
右括号:弹出栈顶左括号并检查是否匹配。
-
-
匹配失败情况:
-
左括号单身(栈非空)。
-
右括号单身(扫描到右括号时栈空)。
-
左右括号类型不匹配。
-
2. 代码实现
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 (不匹配) return false; // 类型检查
}
}
return StackEmpty(S); // 栈空则匹配成功
}
- 使用栈(顺序栈或链栈)实现,注意栈容量问题。
四、队列的应用
队列(FIFO)广泛应用于层次遍历和资源调度。
1. 树的层次遍历
-
按层级访问树节点,队列维护访问顺序。
-
示例:节点1入队后,出队并访问其子节点3、5入队,依次处理。
2. 图的广度优先遍历(BFS)
-
从起点开始,用队列存储待访问节点,确保先访问邻接节点。
-
示例:节点1入队,出队后邻接节点2、8入队,依次扩展。
3. 操作系统中的应用
-
CPU资源分配:就绪进程队列实现FCFS(先来先服务)策略。
-
打印数据缓冲区:队列缓解主机与打印机速度不匹配,管理打印任务顺序。
总结
栈和队列是基础数据结构的核心,栈通过LIFO特性高效处理表达式、递归和括号匹配,队列通过FIFO特性实现遍历和调度。掌握其应用有助于深入理解算法和系统设计。本文基于文档内容系统梳理了关键知识点,嵌入相关图片以增强理解。