栈 Stack
栈是一个先入后出(FILO)的有序列表。栈限制其元素只能在线性表的同一端进行插入和删除操作,允许变化的这一端被称为栈顶(Top),固定的一端称为栈底(Bottom),栈的基本操作有入栈(push)和出栈(pop)
图示:
用数组实现栈
图示:
由于栈的底部是不能移动的,我们只需要一个 top 指针。top 首先会指向 -1,随着元素的加入上移,随着元素的减少下移。
用单链表实现栈
图示:
top指针指向单链表的最后一个元素。添加时在最后一位添加;删除时先遍历到最后一位,然后删除。
用栈实现综合计算器
基本思路:
- 创建两个栈分别记录数字和符号
- 遍历表达式,如果为数字,则直接入数字栈
- 如果为符号,检测符号栈是否为空,如果为空,直接入栈
- 如果不为空,
4.1. 待入栈符号的优先级高于或等于栈中符号的优先级,则直接入栈
4.2. 若待入栈符号的优先级小于栈中符号的优先级,则将数字栈前两位出栈,将当前符号栈中第一位出栈,运算后得到数字加入数字栈中,再加入符号 - 重复上述步骤直到数字栈中只有一位数字
以表达式 3+6*2-2 为例
3, +, 6, *, 2 都是直接加入,当加入 - 时,由于 - 的优先级低于 *,所以执行步骤4.2
然后依次执行 3+12, 15-2 ,得到 13
前缀、中缀、后缀表达式
数学表达式分为三种:前缀、中缀和后缀
我们一般使用的是中缀表达式,即运算符在数字之间,但这种表示方式不利于计算机做运算。因此产生了前缀表达式(波兰式)和后缀表达式(逆波兰式)
中缀计算器更适合用树来实现,后缀计算器更适合用栈实现
前缀表达式
又称波兰式,仅依靠入栈,出栈两种操作就可以完成中缀表达式的全部运算
例如(3+4)*5-6 的前缀表达式为 - * + 3 4 5 6
转换规则
前缀规则类似后缀,详情见后缀表达式
运算规则
- 从右至左扫描前缀表达式,将数字依次存入数字栈
- 遇到运算符时,弹出栈顶的两个数
- 计算结果,压入数字栈中
- 重复上述步骤直到扫描到表达式的最左边
后缀表达式 Reverse polish
又称为逆波兰式,只是将符号放到了数字之后,比前缀表达式更常用
上例的后缀表达式为 3 4 + 5 * 6 -
转换规则
- 创建两个栈,分别保存数字和运算符
- 从左到右遍历中缀表达式,如果是数字,就直接压入数字栈中
- 如果是 “(”,就直接压入符号栈
- 如果是 “)”,就从符号栈中弹出符号,并压入数字栈中,直到将 “(” 弹出
- 如果是非括号符号±*/,则:
- 如果符号栈为空,直接压入符号栈
- 如果符号栈不为空且栈顶为 “(”,直接压入符号栈
- 如果符号栈不为空且栈顶为非括号运算符,判断符号优先级。如果当前符号优先级高于栈顶符号优先级,则直接压入
- 如果当前符号优先级低于或等于栈顶符号优先级,则需要将符号栈内元素出栈,直到有一元素优先级低于当前符号
- 重复直到遍历整个中缀表达式
- 将符号栈元素出栈,压入数字栈中
- 最终数字栈中从栈底往栈顶方向就是完整的后缀表达式
运算规则
- 创建一个栈,用来保存数字
- 从左至右扫描后缀表达式,将数字依次存入数字栈
- 遇到运算符时,弹出栈顶的两个数
- 计算结果,压入数字栈中
- 重复上述步骤直到扫描到表达式的最右边
相关章节
第一节 简述
第二节 稀疏数组 Sparse Array
第三节 队列 Queue
第四节 单链表 Single Linked List
第五节 双向链表 Double Linked List
第六节 单向环形链表 Circular Linked List
第七节 栈 Stack
第八节 递归 Recursion
第九节 时间复杂度 Time Complexity
第十节 排序算法 Sort Algorithm
第十一节 冒泡排序 Bubble Sort
第十二节 选择排序 Select Sort
第十三节 插入排序 Insertion Sort
第十四节 冒泡排序,选择排序和插入排序的总结
第十五节 希尔排序 Shell’s Sort
第十六节 快速排序 Quick Sort
第十七节 归并排序 Merge Sort