定义

栈是限定仅在表尾进行插入和删除操作的线性表。

队列是只允许在一端进行插入操作、而在另一端进行删除操作的线性表。

栈和队列的本质都是线性表,但是是操作受限的线性表。因此它们根据存储方式不同,具有对应线性表的特点。

 

数据结构 - 第三章 栈和队列

栈的特殊之处就在于限制了这个线性表的插入和删除位置,它始终只在栈顶进行。这也就使得栈底是固定的,最先进栈的只能在栈底。因此,栈是后进先出的结构。栈空:top=-1,栈满:top=Maxsize-1。

栈的插入操作,叫作进栈,也称压栈、入栈。PUSH

栈的删除操作,叫作出栈,也有的叫作弹栈。POP

但是最先进栈的元素,不一定就只能是最后出栈,因为入栈的时候可能会有原先的元素已经出栈。n个元素依次入栈的不同出栈次序数量符合卡特兰数的计算公式,即数据结构 - 第三章 栈和队列

共享空间

数据结构 - 第三章 栈和队列

它们是在数组的两端,向中间靠拢。top1 和 top2 是栈1和栈2的栈顶指针,可以想象,只要它们俩不见面,两个栈就可以一直使用。

从这里也就可以分析出来,栈1为空时,就是 top1 等于-1时;而当 top2 等于n时,即是栈2为空时。
若栈2是空栈,栈1的top1等于n-1时,就是栈1满了。反之,当栈1为空栈时,top2等于0时,为栈2满。但更多的情况,两个指针之间相差1时,即 top1 + 1 == top2 为栈满。

链栈

数据结构 - 第三章 栈和队列

栈只是栈顶来做插入和删除操作,由于单链表有头指针,而栈顶指针也是必须的,所以比较好的办法是把栈顶放在单链表的头部。另外,都已经有了栈顶在头部了,单链表中比较常用的头结点也就失去了意义,通常对于链栈来说,是不需要头结点的。

链栈不存在存满的情况,栈空时栈头指针top = null。

应用

1、递归

即函数自己调用自己。每个递归必须至少有一个条件,满足时递归不再进行。函数调用过程中,必须依赖于堆栈保存返回地址、实参、局部变量,重要信息均存放在栈中,才能保证每一个函数执行完毕后能回到正确的位置。代码简单,但是效率低。

2、四则运算表达式求值

中缀表达式:运算符在两个操作数之间。

后缀表达式:运算符在两个操作数之后。(逆波兰式)

括号都是成对出现的,有左括号就一定会有右括号,对于多重括号,最终也是完全嵌套匹配的。这用栈结构正好合适,只有碰到左括号,就将此左括号进栈,不管表达式有多少重括号,反正遇到左括号就进栈,而后面出现右括号时,就让栈顶的左括号出栈,期间让数字运算,这样,最终有括号的表达式从左到右巡查一遍,栈应该是由空到有元素,最终再因全部匹配成功后成为空栈的结果。

但是此时仍然不能解决加减乘除的优先级问题,因此引入了逆波兰式。

数据结构 - 第三章 栈和队列  ——>  数据结构 - 第三章 栈和队列

后缀表达式计算:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,直到最终获得结果。

中缀表达式转后缀表达式:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。

 

队列

队列是一种先进先出的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。

为了避免当只有一个元素时,队头和队尾重合使处理变得麻烦,所以引入两个指针,front 指针指向队头元素,rear 指针指向队尾元素的下一个位置,这样当 front 等于rear时,此队列不是还剩一个元素,而是空队列。

对于循环队列与链队列的比较,可以从两方面来考虑。

从时间上,其实它们的基本操作都是常数时间,即都为O(1)的, 不过循环队列是事先申请好空间,使用期间不
释放,而对于链队列,每次申请和释放结点也会存在一些时间开销,如果入队出队频繁,则两者还是有细微差异。

对于空间上来说,循环队列必须有一个固定的长度,所以就有了存储元素个数和空间浪费的问题。而链队列不存在这个问题,尽管它需要一个指针域,会产生一些空间上的开销,但也可以接受。所以在空间上,链队列更加灵活。
总的来说,在可以确定队列长度最大值的情况下,建议用循环队列,如果你无法预估队列的长度时,则用链队列。

循环队列

循环队列即将队列改成头尾相接的顺序存储结构,但面临着数组溢出的情况。

数据结构 - 第三章 栈和队列

rear == front时,我们无法确定队空或队满。解决方法有两种:

1、设置一个标志变量flag,当 front == rear,且 flag = 0 时为队列空,当 front == rear,且flag= 1时为队列满。

2、当队列空时,条件是front = rear。当队列满时,我们修改其条件,保留一个元素空间。也就是说,队列满时,数组中还有一个空闲单元。即条件为 (rear+1)%size == front。

链队列

队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已,我们把它简称为链队列。为了操作上的方便,我们将队头指针指向链队列的头结点,而队尾指针指向终端结点。

队空时,头尾指针均指向头结点。

 

参考教材:

《数据结构与算法》,熊岳山著,清华大学出版社,2016,第二版

《2020年数据结构考研复习指导》,电子工业出版社,2020

相关文章: