大话数据结构(第四章 栈与队列)
栈是限定仅在表尾进行插入和删除操作的线性表。
队列是只允许在另一端进行插入操作、而在另一端进行删除操作的线性表。
总结起来一句话形容:
栈:先进后出,后进先出(Last In First Out)。
允许插入和删除的端称之为栈顶(top),另一端称之为栈底(bottom),没元素的为空栈。简称LIFO结构。
进栈、压栈、弹栈
1、栈的抽象数据类型
栈,实际上线性表的操作特性它都具备,在插入和删除上有些变化,并改名为push和pop
2、栈的顺序存储结构及实现
栈、顺序栈;用下标为0的一端作为栈底
定义一个top变量指示栈顶元素的位置,空栈时,top定为-1
3、两栈共享空间
一个栈如果空间用满了就有可能溢出,为了充分利用空间。
我们把两个栈的未利用空间共享。
具体操作方法如下:
一个栈有两端,一个数组有两端,让一个栈的栈底为数组的起始,另一个栈的末端为数组长度n-1处,这样当两个栈压栈时候,是从两端向中间延伸。
栈满的情况,当两个栈顶相差1时,栈满。
使用这种栈结构方式一般是两个栈空间有相反的需求关系的时候。
4、栈的链式存储结构及实现
链的顺序存储结构,简称链栈。
与单链表类似,只是插入删除有所区别,他们的进出事件复杂度均为O(1)
顺序栈与链栈 事件复杂度一样,顺序栈需要一个固定的长度,可能存在空间浪费问题,优势是存取方便,链栈每一个元素都有指针域,增加内存开销。
4、栈的作用
有的人想,既然都用数组或者链表能完成,为什么不直接用他们,非要封装这样的数据结构呢?
其实为什么要做飞机、汽车、轮船呢,世界上很多位置都能用脚抵达,但是我们关注的是到达而不是去的过程,这个而过程可以用各种方式封装起来,栈也是这样的作用。栈的引入简化了程序设计问题,划分了不同的关注层次,使得思考范围缩小,聚焦我们的核心问题,而像数组,如果分散精力去考虑数组下标的增减等细节问题,会浪费精力,掩盖问题本质。现在很多高级语言,都有对栈的结构封装,不用关注细节,直接使用Stack的push和pop方法,非常方便。
5、栈的应用-递归
栈有一个很重要的应用,在程序设计语言中实现了递归。
例子:斐波那契数列实现(Fibonacci)
一对兔子出生两个月后就有繁殖能力,一对兔子每个月能生出一队小兔子,假设兔子不死,一年后可以繁殖多少对兔子?
一种方式是使用for循环迭代,另一方面是递归调用自己。每一层递归,函数的局部变量、参数值、返回的地址都压入栈中,退回阶段,位于顶端的局部变狼、参数值好返回地址呗弹出,用于执行调用层次中其余代码部分。
递归的前行和回退
6、栈的应用-四则运算表达式求值
四则运算
后缀表达式,从左到右遍历后缀表达式,遇到数字进栈,遇到符号则取出两个数字运算,结果再进栈。
平时使用的四则运算表达式称作中缀表达式
7、队列的定义
允许一段进行插入操作,而另一端进行删除操作的线性表(First In First Out)
队列的抽象数据类型:插入只能在队尾,删除只能在队头进行。
同样的,队列是线性表,也有顺序存储和链式存储。
队列的顺序存储中,取元素从队头出,会移动元素
循环队列定义:队列头尾相接的顺序存储结构称为循环队列
8、队列的链式存储结构及实现
尾进头出