algorithm-base/animation-simulation/数据结构和算法/关于栈和队列的那些事.md
2021-05-14 15:31:45 +08:00

164 lines
8.5 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 希望这篇文章能合你的胃口
> 如果阅读时发现错误或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈
>
> 感谢支持该仓库会一直维护希望对各位有一丢丢帮助
>
> 另外希望手机阅读的同学可以来我的 <u>[**公众号袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)</u> 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击<u>[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)</u>进入。
大家在学习数据结构的时候应该都学习过栈和队列对他俩的原理应该很熟悉了栈是先进后出队列是后进后出下面我们通过这篇文章来帮助小伙伴们回忆一下栈和队列的那些事
阅读完这篇文章你会有以下收获
了解栈和队列的意义
了解栈和队列的实现方式
了解循环队列
学会中缀表达式转后缀表达式
学会后缀表达式的运算
## 这是栈
### 栈模型
**stack是限制插入和删除只能在一个位置上进行的表**该位置是表的末端叫做栈的顶top对栈的基本操作有push(进栈)和pop(出栈),前者相当于插入后者则是删除最后插入的元素
栈的另一个名字是LIFO先进后出普通的清空栈的操作和判断是否空栈的测试都是栈的操作指令系统的一部分我们对栈能做的基本上也就是push和pop操作
该图描述的模型只象征着push是输入操作pop和top是输出操作
![栈和队列1](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/栈和队列1.1wjbrl9iudk0.png)
下图表示进行若干操作后的一个抽象的栈一般的模型是存在某个元素位于栈顶而该元素是唯一可见元素
![2222](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/2222.1ksit1l8tlr4.png)
### 栈的实现
因为栈是一个表因此能够实现表的方法都可以实现栈ArrayList和LinkedList都可以支持栈操作
刷题时我们可以直接使用Stack类来进行创建一个栈刷题时我们可以通过下列代码创建一个栈下面两种方式哪种都可以使用
```
Deque<TreeNode> stack = new LinkedList<TreeNode>();//类型为TreeNode
Stack<TreeNode> stack = new Stack<TreeNode>();
```
### 栈的应用
栈在现实中应用场景很多大家在刷题时就可以注意到很多题目都可以用栈来解决的下面我们来说一个比较常用的情景数字表达式的求值
不知道大家是否还记得那句口令先乘除后加减从左算到右有括号的话就先算括号里面的这是我们做小学数学所用到的四则运算中括号也是其中的一部分先乘除后加减使运算变的复杂加上括号后甚之那么我们有什么办法可以让其变的更好处理呢波兰数学家**Jan Łukasiewicz**想到了一种不需要括号的后缀表达式我们也将它称之为逆波兰表示不用数学家名字命名的原因有些尴尬居然是因为他的名字太复杂了所以用了国籍来表示而不是姓名所以各位小伙伴以后给孩子起名字的时候不要太复杂啊
> ·武卡谢维奇[波兰语](https://baike.baidu.com/item/波兰语)*Jan Łukasiewicz*1878年12月21日[乌克兰](https://baike.baidu.com/item/乌克兰)利沃夫 - 1956年2月13日爱尔兰都柏林[波兰](https://baike.baidu.com/item/波兰)数学家,主要致力于[数理逻辑](https://baike.baidu.com/item/数理逻辑)的研究。著名的波兰表示法逆波兰表示法就是他的研究成果。
#### 中缀表达式转为后缀表达式
我们通过一个例子来说明如何将中缀表达式转为后缀表达式
中缀:9 + ( 3 - 1 ) * 3 + 10 / 2
后缀:9 3 1 - 3 * + 10 2 / +
规则
1.从左到右遍历中缀表达式的每个数字和符号若是数字就输出直接成为后缀表达式的一部分不进入栈
2.若是符合则判断其与栈顶符号的优先级是右括号或低于栈顶元素则栈顶元素依次出栈并输出等出栈完毕当前元素入栈
3.遵循以上两条直到输出后缀表达式为止
老样子大家直接看动图吧简单粗暴清晰易懂
![中缀转后缀](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/中缀转后缀.712hv6fxip40.gif)
#### 后缀表达式计算结果
中缀:9 + ( 3 - 1 ) * 3 + 10 / 2=20
后缀:9 3 1 - 3 * + 10 2 / +
后缀表达式的值也为20那么我们来了解一下计算机是如何将后缀表达式计算为20的
规则
1.从左到右遍历表达式的每个数字和符号如果是数字就进栈
2.如果是符号就将栈顶的两个数字出栈进行运算并将结果入栈一直到获得最终结果
下面大家 继续看动图吧
![后缀运算](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/后缀运算.38havvkp8k40.gif)
为了用动图把逻辑整的清晰明了十几秒的动图就要整半个多小时改进好几遍如果觉得图片对你有帮助的话就点个赞和在看吧
## 这是队列
### 队列模型
像栈一样队列queue也是表然而使用队列时插入在一端进行而删除在另一端进行遵守先进先出的规则所以队列的另一个名字是FIFO
队列的基本操作是入队enqueue:它是在表的末端(队尾(rear)插入一个元素出队dequeue:出队他是删除在表的开头队头(front)的元素
下面模型只象征着输入输出操作
![image-20201102213300674](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201102213300674.1yvt4eulwri8.png)
具体模型
![image-20201102214029660](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201102214029660.7fol7xl7uz40.png)
### 队列的实现
队列我们在树的层次遍历时经常使用后面我们写到树的时候会给大家整理框架队列同样也可以由数组和LinkedList实现刷题时比较常用的方法是
```
Queue<TreeNode> queue = new LinkedList<TreeNode>();
```
### 循环队列
循环队列的出现就是为了解决队列的假溢出问题何为假溢出呢我们运用数组实现队列时数组长度为5我们放入了[1,2,3,4,5],我们将12出队此时如果继续加入6时因为数组末尾元素已经被占用再向后加则会溢出但是我们的下标0和下标1还是空闲的所以我们把这种现象叫做假溢出
例如我们在学校里面排队洗澡一人一个格当你来到澡堂发现前面还有两个格但是后面已经满了你是去前面洗还是等后面格子的哥们洗完再洗肯定是去前面的格子洗除非澡堂的所有格子都满了我们才会等
所以我们用来解决假溢出的方法就是后面满了就再从头开始也就是头尾相接的循环我们把队列的这种头尾相接的顺序存储结构成为循环队列
![循环队列](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/循环队列.1841k3lsp7cw.gif)
我们发现队列为空时front == rear队列满时也是front == rear那么问题来了我们应该怎么区分满和空呢
我们可以通过以下两种方法进行区分
1.设置标记变量flag;当front==rear 时且flag==0时为空当front==rear且rear为1时且flag==1时为满
2.当队列为空时front==rear,当队列满是我们保留一个元素空间也就是说队列满时数组内还有一个空间
![image-20201102222857190](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201102222857190.4trq9b6gfjc0.png)
![image-20201102222914762](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201102222914762.34b1o0cqwse0.png)
然后我们再根据以下公式则能够判断队列满没满了
(rear+1)%queuesize==front
queuesize,代表队列的长度上图为5我们来判断上面两张图是否满4+1%5==01+1%5==3
两种情况都是满的,over
为了用动图把逻辑整的清晰明了十几秒的动图就要整半个多小时改进好几遍如果觉得图片对你有帮助的话就点个赞和在看吧