栈和队列

 一. 摘要

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

队列是只荀彧在一端进行插入操作,在另一端进行删除操作的线性表;

二. 栈的定义

    定义:栈是一个后进先出的线性表(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        出栈

}

七. 栈的应用

  1. 递归

  2. 四则运算表达式求值

八. 队列的定义

    定义:队列是一个先进先出(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      出队

}

 

posted @ 2019-12-04 14:44  Super-Yan  阅读(186)  评论(0编辑  收藏  举报