栈和队列的应用
栈与表达式求值
中缀表达式转后缀表达式
优先级>=栈顶符号的时候需要弹出。
输入:中缀表达式 infixExp (以字符或字符串数组形式)
输出:后缀表达式 postfixExp (字符串或数组)
1. 创建一个空栈 operatorStack 用于存放运算符
2. 创建一个空列表 postfixList 用于存放后缀表达式元素
3. 从左到右遍历中缀表达式中的每个元素 token
3.1 如果 token 是操作数(数字或变量)
将 token 直接添加到 postfixList
3.2 如果 token 是左括号 "("
将 token 压入 operatorStack
3.3 如果 token 是右括号 ")"
从 operatorStack 弹出运算符,依次添加到 postfixList,直到弹出左括号 "("(左括号不加入 postfixList)
3.4 如果 token 是运算符 op(如 +, -, *, /, ^)
while operatorStack 不为空 且 栈顶运算符 topOp 的优先级 >= 当前运算符 op 的优先级
(若运算符结合性为左结合,使用 >= 比较;右结合则使用 >)
弹出 topOp 并添加到 postfixList
将当前运算符 op 压入 operatorStack
4. 遍历结束后,将 operatorStack 中剩余运算符依次弹出并添加到 postfixList
5. 返回 postfixList 作为后缀表达式
运算符优先级表(从高到低)
| 运算符 | 说明 | 优先级值(示例) |
|---|---|---|
() | 括号 | 最高(特殊处理) |
^ | 乘方 | 4 |
* / | 乘、除 | 3 |
+ - | 加、减 | 2 |
| 其他 | 比较低的运算符或括号 | 1 或 0 |
注意事项
- 优先级和结合性必须明确,否则转换结果错误。
- 括号匹配:输入表达式括号必须匹配,否则弹栈时可能找不到对应左括号。
- 操作数格式:支持多位数字或变量时,解析时应正确识别完整操作数。
- 空格或分隔符:表达式中元素应清晰分隔,方便逐个处理。
- 错误处理:遇到非法字符或格式应有异常处理。
- 运算符集:根据需求支持的运算符不同,优先级和结合性规则也要相应调整。
人工中缀转后缀
在人工转换中缀表达式到后缀表达式时,一种直观的方法是利用“加括号”和“运算符后移”的思路:
-
根据运算符的优先级,为每个操作数和运算符组合添加括号,使其成为完全括号化的表达式。
-
例如,对于
A + B * C:B * C优先级高,先加括号:A + (B * C)- 然后
A + (B * C)整体加括号:(A + (B * C))
-
对于
(A + B) * C:A + B优先级高(括号强制),先加括号:((A + B) * C)
-
完全括号化后,将每个运算符“移动”到其对应右括号的外面。
-
最后,移除所有括号。
-
示例 1:
A + B * C- 完全括号化:
(A + (B * C)) - 运算符后移:
(A (B C *) +) - 移除括号:
A B C * +
- 完全括号化:
-
示例 2:
(A + B) * C- 完全括号化:
((A + B) * C) - 运算符后移:
((A B +) C *) - 移除括号:
A B + C *
- 完全括号化:
后缀表达式求值
输入:后缀表达式 postfixExp (以空格分隔的字符串或数组)
输出:表达式计算结果
1. 创建一个空栈 stack 用于存放操作数
2. 从左到右遍历后缀表达式中的每个元素 token
2.1 如果 token 是数字(操作数)
将 token 转换为数字,压入栈 stack
2.2 否则 token 是运算符 op(如 +, -, *, /)
从栈中弹出两个操作数,先弹出的赋值给右操作数 b,后弹出的赋值给左操作数 a
根据运算符 op 计算 result = a op b
将 result 压入栈 stack
3. 遍历结束后,栈顶元素即为表达式的计算结果,弹出并返回该结果注意事项
- 操作数顺序:弹出栈顶的两个操作数时,先弹出的为右操作数,后弹出的为左操作数,计算时顺序不能颠倒(如 a op b)。
- 运算符合法性:输入的后缀表达式必须是合法的,运算符数量和操作数数量匹配,避免栈空时弹栈错误。
- 除法处理:除法时注意除数不能为零,且根据需求处理整数除法或浮点除法(整数除法可能只保留整数部分)。
- 数字格式:支持多位数字和负数时,解析数字时应正确识别完整数字。
- 空格分隔:后缀表达式中元素应当用空格或其他明确分隔符分开,方便逐个读取。
- 栈初始化和结束状态:开始时栈为空,结束时栈中应仅剩一个元素,即最终结果,若多于一个元素说明表达式不合法。
综上,后缀表达式求值的核心是利用栈结构,遇数字入栈,遇运算符弹出两个数字计算后再入栈,遍历完表达式后栈顶即为结果
队列在广度优先遍历的应用
广度优先遍历(Breadth-First Search, BFS)是一种图或树的遍历算法,它从起始节点开始,探索其所有相邻节点,然后是这些相邻节点的未访问邻居,以此类推,逐层向外扩展。队列的先进先出(FIFO)特性使其成为实现 BFS 的理想数据结构。
核心思想: 队列保证了节点是按照它们被发现的顺序(即距离起始节点的距离)进行访问的。先被发现的节点(更靠近起始节点)会先被处理,从而实现逐层遍历的效果。
算法步骤:
- 初始化:
- 创建一个空队列
Q。 - 创建一个集合或数组
visited用于记录已访问的节点,避免重复访问和死循环。 - 将起始节点
s标记为已访问,并将其加入队列Q。
- 创建一个空队列
- 遍历:
- 当队列
Q不为空时,重复以下步骤:- 从队列
Q中出队一个节点u。 - 处理节点
u(例如,打印节点值,检查是否为目标节点等)。 - 遍历节点
u的所有未访问邻居v:- 将邻居
v标记为已访问。 - 将邻居
v入队Q。
- 将邻居
- 从队列
- 当队列
示例应用:
- 二叉树层次遍历:按照从上到下、从左到右的顺序逐层访问二叉树中的所有节点。
- 查找最短路径: 在无权图中,BFS 可以找到从起始节点到所有其他节点的最短路径(按边数计算)。
- 社交网络分析: 查找“六度分隔理论”中的连接路径。
- 网络爬虫: 从一个起始页面开始,逐层爬取链接的页面。
- 垃圾回收: 标记 - 清除算法中,从根对象开始遍历可达对象。