个人学习数据结构算法笔记系列 栈和队列
目录
参考 https://github.com/chefyuan/algorithm-base
(一)栈
1.栈模型
栈(stack)是限制插入和删除只能在一个位置上进行的表。该位置是表的末端叫做栈的顶(top),对栈的基本操作有push(进栈)和pop(出栈),前者相当于插入,后者则是删除最后插入的元素。
栈的另一个名字是LIFO(先进后出)表。普通的清空栈的操作和判断是否空栈的测试都是栈的操作指令系统的一部分,我们对栈能做的基本上也就是push和pop操作。
下图表示进行若干操作后的一个抽象的栈。一般的模型是,存在某个元素位于栈顶,而该元素是唯一可见元素
2.栈的实现
Deque<TreeNode> stack = new LinkedList<TreeNode>();//类型为TreeNode
Stack<TreeNode> stack = new Stack<TreeNode>();
3.栈的应用
将中缀表达式转为后缀表达式
中缀:9 + ( 3 - 1 ) * 3 + 10 / 2
后缀:9 3 1 - 3 * + 10 2 / +
规则
1.从左到右遍历中缀表达式的每个数字和符号,若是数字就输出(直接成为后缀表达式的一部分,不进入栈)
2.若是符合则判断其与栈顶符号的优先级,是右括号或低于栈顶元素,则栈顶元素依次出栈并输出,等出栈完毕,当前元素入栈。
3.遵循以上两条直到输出后缀表达式为止。
(二)队列
1.队列模型
像栈一样,队列(queue)也是表。然而使用队列时插入在一端进行而删除在另一端进行,遵守先进先出的规则。所以队列的另一个名字是(FIFO)。
队列的基本操作是入队(enqueue):它是在表的末端(队尾(rear)插入一个元素。出队(dequeue):出队他是删除在表的开头(队头(front))的元素。
2.队列的实现
Queue<TreeNode> queue = new LinkedList<TreeNode>();
3.循环队列
循环队列的出现就是为了解决队列的假溢出问题。何为假溢出呢?我们运用数组实现队列时,数组长度为5,我们放入了[1,2,3,4,5],我们将1,2出队,此时如果继续加入6时,因为数组末尾元素已经被占用,再向后加则会溢出,但是我们的下标0,和下标1还是空闲的。所以我们把这种现象叫做“假溢出”。
例如,我们在学校里面排队洗澡一人一个格,当你来到澡堂发现前面还有两个格,但是后面已经满了,你是去前面洗,还是等后面格子的哥们洗完再洗?肯定是去前面的格子洗。除非澡堂的所有格子都满了。我们才会等。
所以我们用来解决假溢出的方法就是后面满了,就再从头开始,也就是头尾相接的循环,我们把队列的这种头尾相接的顺序存储结构成为循环队列。
我们发现队列为空时front == rear,队列满时也是front == rear,那么问题来了,我们应该怎么区分满和空呢?
我们可以通过以下两种方法进行区分,
1.设置标记变量flag;当front==rear 时且flag==0时为空,当front==rear且rear为1时且flag==1时为满
2.当队列为空时,front==rear,当队列满是我们保留一个元素空间,也就是说,队列满时,数组内还有一个空间。