栈和队列
一. 摘要
栈是限定仅在表尾进行插入和删除操作的线性表;
队列是只荀彧在一端进行插入操作,在另一端进行删除操作的线性表;
二. 栈的定义
定义:栈是一个后进先出的线性表(LIFO),比如手枪弹夹,后装入的子弹会先射出。插入和删除操作在同一端。
允许插入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈。栈的插入操作,叫做进栈,也称为压栈、入栈。栈的删除操作称为出栈
根据栈的定义,首先它是一个线性表,也就是说,栈元素具备线性关系,有线性表的全部特性。栈是线性表的一种特殊形式,是线性表的子集。
三. 栈的抽象数据类型
对于栈来讲,理论上线性表的操作特性它都具备,可由于它的特殊性,所以针对它的操作上会有些变化。特别是插入和删除操作,我们改名为push和pop。
Data 数据元素
Push(T model) 插入新元素model到栈中并成为栈顶元素
Pop(T model) 删除栈中栈顶元素,并用model返回其值
IsEmpty() 返回栈是否为空
ClearStack() 将栈清空
Esists(T model) 栈中是否存在model元素
Length() 返回栈的长度
四. 栈的顺序存储结构
既然栈是线性表的特例,那么栈的顺序存储其实是线性表顺序存储的简化,我们简称为顺序栈。线性表是用数组来实现的,想想看,对于栈这种只能一头插入删除的线性表来说,用数组哪一端来作为栈顶和栈底比较好?
答案是:下标为0的一端作为栈底比较好,因为首元素都存在栈底,变化最小,所以让它作栈底。
栈顺序结构的数据模型
Type 栈存储的数据类型
MaxSize 栈的长度
Data[MaxSzie] 存储栈数据的数组
Push(T model) 进栈
Pop(T model) 出栈
top 栈顶指针
五. 两栈共享空间
其实栈的顺序存储还是挺方便的,因为他只准栈顶进出元素,所以不存在线性表插入和删除时需要移动大量元素的问题。不过他有一个很大的缺陷,就是必须实现确定数组存储空间大小,万一不够用了,就需要编程手段来扩展数组的容量,非常麻烦。对于一个栈,我们只能尽量考虑周全,设计出合适大小的数组来处理,但对于两个相同类型的栈,我们却可以做单最大限度的利用其实现开辟的存储空间来进行操作。
如果有两个相同类型的栈,我们为它们各自开辟了空间,很可能其中一个栈溢出了,另一个还有很多存储空间空闲。针对这样的情况,我们完全可以用一个数组来存储两个栈,只不过需要一些小技巧。
一个数组有两个端点,让下标为0的一端作为一个栈的栈底,下标为数组长度n-1的一端作为另一个栈的栈底。两个站如果新增了元素,就是两端向中间点延伸。top1、top2分别作为栈1、栈2的栈顶指针,只要他们两不见面,两个站就可以一直使用。
栈1位空栈时 top1=-1,栈2为空栈 top2=n。当top1+1=top2时,栈1 栈2位栈满。
判断栈是否为空 top=-1
判断栈是否为满栈 top=MaxSize-1
六. 栈的链式存储结构
在链式存储结构中,栈顶应该放在链表的头部还是尾部呢?由于链式结构需要有一个头部指针,栈也需要有一个栈顶指针,那干嘛不让它们合二为一呢?所以最好的方法时将栈顶放在头部,栈的链表也就不需要头部指针了。
对于栈的链式存储结构,基本不存在栈满的情况,除非内存已经没有足够的使用空间了。
对于空栈来说,链表原定义是栈顶指针指向空,即top=null
栈链式结构数据模型
Node{
Data 数据
Next 下一个结点
}
Link{
Node top 栈顶指针
Count 栈的长度
Push 进栈
Pop 出栈
}
七. 栈的应用
-
递归
-
四则运算表达式求值
八. 队列的定义
定义:队列是一个先进先出(FIFO)的线性表,在一端插入 另一端删除。
比如像移动、联通、电信等客服电话,客服人员与客户相比总是少数,在所有的客服人员都占线的情况下,客户会被要求等待,直到有某个客服人员空下来,才能让最先等待等待客户接通电话。这里就是将所有当前拨打客服电话的客户进行了排队处理。
允许插入的一端成为队尾,允许删除的一端成为队头。
九. 队列的抽象数据模型
同样是线性表,队列也有类似线性表的各种操作,不同的就是插入数据只能在队尾进行,删除数据只能在队头进行。
Data 数据元素
EnQueue(T model) 插入新元素model到栈中并成为栈顶元素
(T model) 删除栈中栈顶元素,并用model返回其值
IsEmpty() 返回栈是否为空
ClearStack() 将栈清空
Esists(T model) 栈中是否存在model元素
Length() 返回栈的长度
十. 队列的顺序存储结构
不同于栈的顺序存储,队列是在一端插入另一端删除的,也就是说每次执行出队操作时都需要移动大量的数据元素,造成性能损耗。
有什么办法优化呢?先来看看为什么每次出队都要移动元素。这是因为队头在下标为0的位置,就像去购票,第一个位置的人购买成功离开了,后边的人就需要往前进一位,下一个被服务(待出队)的对象还是第一个位置的人。在现实中这种情况没有办法解决,但是在计算机中就不一样了,我们可以维护一个标识待出队的数据元素的位置的变量,每次有出队操作,只需要修改这个变量就可以了。这就相当于,当一个购票人离开后,售票员就移动往前一格来服务下一个购票人,购票人的队伍就不需要移动了。
队列顺序结构数据模型
Type 栈存储的数据类型
MaxSize 栈的长度
Data[MaxSzie] 存储栈数据的数组
EnQueue(T model) 进队
DeQueue(T model) 出队
front 头指针
rear 尾指针
十一. 队列的链式存储结构
队列的链式存储结构,其实就是线性表的单链表,只不过他只能尾进头出而已,我们把它简称为链队列。为了操作上的方便,我们将队头指针指向队列的头结点,而队尾指针指向终端结点。空队列是,front和rear都指向头结点。
队列链式存储结构数据模型
Node{
Data 数据
Next 下一个结点
}
Link{
Node front 队头指针
Node rear 队尾指针
Count 队列的长度
EnQueue 进队
DeQueue 出队
}