820数据结构(3)栈和队列

考纲(无算法实现)

  1. 线性表的定义
  2. 线性表的基本操作及在顺序存储及链式存储上的实现
  3. 各种变形链表(循环链表、双向链表、带头结点的链表等)的表示和基本操作的实现
  4. 递归过程的特点及实现方法
  5. 栈和队列的基本概念;栈和队列的顺序存储结构、链式储存结构及其存储特点
  6. 栈和队列的应用
  7. 循环队列的判满、判空方法
  8. 特殊矩阵的压缩储存

一、栈

1、栈的基本概念

  1. 栈(Stack)是只允许在一端进行插入或删除操作的线性表限定 这种线性表只能在某一端进行插入和删除。
  2. 栈只能在栈顶进行插入和删除操作。
  3. 栈的操作特性:LIFO后进先出。
  4. 栈的数学特质 :n个不同元素进栈,出栈元素不同排列的个数为
    卡特兰数卡特兰数

2、栈的基本操作

直接调用即可

  • InitStack(&S):初始化一个空栈S。
  • StackEmpty(S):判断一个栈是否为空,若栈S为空则返回true,否则返回false。
  • Push(&S, x):进栈,若栈S未满,则将x加入使之成为新栈顶。
  • Pop(&S, &x):出栈,若栈s非空,则弹出栈顶元素,并用x返回。
  • GetTop(S, &x):读栈顶元素,若栈s非空,则用x返回栈顶元素。
  • DestroyStack(&S):销毁栈,并释放栈s占用的存储空间。

栈和队列是操作受限的线性表,因此不是任何对线性表的操作都可以作为栈和队列的操作。比如,不可以随便读取栈或队列中间的某个数据。

3、栈的两种存储方式

(1)顺序栈

  1. 定义:采用顺序存储的栈。利用一组地址连续的存储单元存放自栈底到栈顶的数据元素,同时附设一个指针(top)指示当前栈顶元素的位置。
  2. 顺序存储类型(了解)
    #define MaxSize 50   
    typedef struct{
    	ElemType data[MaxSize];  //存放栈中元素
    	int top;                 //栈顶指针
    }SqStack;
    
  3. 栈的判空、判满(按实际情况定)
    栈顶指针:S.top,初始设置S.top = -1;栈顶元素:S.data[S.top]
    栈空条件: S.top == -1判满条件: S.top == MaxSize-1;栈长:S.top+1
  4. 基本运算(了解操作细节)
    • top指向栈顶元素(栈顶指针初始化为S.top = -1
      • 进栈操作:S.data[++S.top] = x
      • 出栈操作:x = S.data[S.top--]
    • top指向栈顶元素的下一位置(栈顶指针初始化为S.top = 0
      • 进栈操作:S.data[S.top++] = x
      • 出栈操作:x = S.data[--S.top]
  5. 共享栈
    • 定义:利用栈底位置相对不变的特性,可让两个顺序栈共享一个一维数组空间,将两个栈的栈底分别设置在共享空间的两端,两个栈顶向共享空间的中间延伸。
      在这里插入图片描述
    • top0 = -1时0号栈为空,top1 = MaxSize时1号栈为空;仅当两个栈顶指针相邻(top1-top0=1)时,判断为栈满。

(2)链栈(比较优缺点即可)

在这里插入图片描述

  • 优点:便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。便于结点的插入与删除。

二、队列

1、队列的基本概念

  • 定义:队列(Queue)是一种操作受限的线性表 ,只允许在表的一端进行插入 ,而在表的另一端进行删除
  • 队列的操作特性:FIFO先进先出。

2、队列的基本操作

同栈,操作受限。

  • InitQueue(&Q):初始化队列,构造一个空队列Q。
  • QueueEmpty(Q):判队列空,若队列Q为空则返回true,否则返回false。
  • EnQueue(&Q, x):入队,若队列Q未满,则将x加入,使之成为新队尾。
  • DeQueue(&Q, &x):出栈,若队列Q非空,删除队头元素,并用x返回。
  • GetHead(Q, &x):读栈顶元素,若队列Q非空,则将队头元素赋值给x。

3、队列的存储方式

(1)队列的顺序存储(不要求实现)

[1] 顺序存储

在这里插入图片描述

  1. 初始状态(队空条件):Q.front == Q.rear == 0
  2. 队满条件
    • 不能用Q.rear == MaxSize作为队列满的条件。
      图(d)中队列只有一个元素,但仍满足该条件。此时入队出现“上溢出”,但这种溢出并不是真正的溢出,在data数组中依然存在可以存放元素的空位置,是一种“假溢出”。
    • 假溢出(填空)
      - 定义1:系统作为队列用的存储区还没有满,但队列却发生了溢出。
      - 定义2:因顺序队列进行大量的出队入队操作后,导致前部队列虽然有存储:位点,但后续入队操作无法进行的溢出。
      - 利用循环队列进行解决“假溢出”。
[2] 循环队列

在这里插入图片描述
判队空/队满的三种处理方式

  1. 牺牲一个单元来区分,入队时少用一个队列单元。约定“队头指针在队尾指针的下一位置作为队满的标志”。
    队满条件(Q.rear+1)%MaxSize == Q.front
    队空条件Q.front == Q.rear
    队列中元素的个数:(Q.rear - Q.front + MaxSize) % MaxSize
  2. 类型中增设表示元素个数的数据成员。
    队满条件:Q.size == 0
    队空条件:Q.size == MaxSize
  3. 类型中增设tag数据成员。
    队空条件:tag=0时,因删除导致Q.front == Q.rear
    队满条件:tag=1时,因插入导致Q.front == Q.rear

(2)队列的链式存储(比较优缺点)

  • 不带头结点的链式队列
    在这里插入图片描述
  • 带头结点的链式队列
    在这里插入图片描述
  • 优点:用单链表表示的链式队列特别适合于数据元素变动比较大的情形,而且不存在队列满且产生溢出的问题。当程序中要使用多个队列,使用链式队列就不会出现存储分配不合理和“溢出”问题。

(3)双端队列(选填)

  1. 定义:允许两端都可以进行入队和出队操作的队列。元素的逻辑结构仍是线性结构。将队列的两端分别称为前端和后端,两端都可以入队和出队。
    在这里插入图片描述

  2. 输出受限的双端队列:允许在一端进行插入和删除,但在另一端只允许插入的双端队列。
    在这里插入图片描述

  3. 输入受限的双端队列:允许在一端进行插入和删除,但在另一端只允许删除的双端队列。
    若限定双端队列从某个端点插入的元素只能从该端点删除,则该双端队列就蜕变为两个栈底相邻接的栈。
    在这里插入图片描述

  4. 比较哪种序列可以得到/得不到

例题理解:(实际上直接代入验证即可)
在这里插入图片描述
在这里插入图片描述

三、栈和队列的应用(考得少)

1、栈在括号匹配中的应用

  • 算法的思想(与栈的思想吻合)(了解掌握)
    1. 初始设置一个空栈,顺序读入括号。
    2. 若是右括号,则或者使置于栈顶的最急迫期待得以消解,或者是不合法的情况(括号序列不匹配,退出程序)
    3. 若是左括号,则作为一个新的更急迫的期待压入栈中,自然使原有的在栈中的所有未消解的期待的急迫性降了一级。算法结束时,栈为空,否则括号序列不匹配。

2、栈在表达式求值中的应用(没考过)

  • 通过后缀表示计算表达式值的过程:
    • 顺序扫描表达式的每一项,然后根据他的类型做如下操作:
      • 若该项是操作数,将其压入栈中;
      • 若该项是操作符< op >,则连续从栈中退出两个操作数Y和X,形成运算指令X< op >Y,并将计算结果重新压入栈中。
    • 当表达式的所有项都扫描并处理完后,栈顶存放的就是最后的计算结果。

例题:中缀表达式A + B * ( C - D ) - E / F

  • 解答Step1:中缀转后缀
    • 方法1:根据操作符优先级
      • 运算符的优先级如下表:
        在这里插入图片描述
      • 在表达式后面加上符号#,表示表达式结束,具体转换过程如下:
        在这里插入图片描述
    • 方法2:
      • 运算规则
        • 操作数直接输出
        • 操作符
          • 若为"(",入栈;
          • 若为“)”,则依次把栈中运算符加入后缀表达式,直到出现"(",从栈中删除“(”。
          • 若为除括号外的其他运算符,当其优先级高于除"("外的栈顶运算符时,直接入栈。否则直接从栈顶开始,依次弹出比当前处理的运算符优先级高和相等的运算符,直到一个比它优先级低的或遇到了一个左括号。
      • 计算如下在这里插入图片描述
    • 方法3:手工
      • 步骤
        • 按照运算符的优先级对所有的运算单位加括号
        • 转换为前缀或后缀表达式
          • 前缀:把运算符号移动到对应的括号前面
          • 后缀:把运算符号移动到对应的括号后面
      • 计算过程
        在这里插入图片描述
  • 解答Step2:求值
    在这里插入图片描述

3、栈在递归中的应用(后续树的算法会用)

  1. 递归定义:若在一个函数、程序或数据结构的定义中又应用了它自身,则这个函数、过程或数据结构称为是递归定义的,简称递归。
  2. 斐波那契数列为例(了解)
    在这里插入图片描述
    int Fib(int n){
    	if(n==0)
    		return 0;                    //边界条件
    	else if(n==1)
    		return 1;                    //边界条件
    	else
    		return Fib(n-1) + Fib(n-2)   //递归表达式
    }
    

4、队列在层次遍历中的应用(后续树的算法会用到)

  • 层次遍历的简单描述
    • ① 根结点入队。
    • ② 若队空(所有结点都已处理完毕),则结束遍历;否则重复③操作。
    • ③ 队列中第一个结点出队,并访问之。若其有左孩子,则将左孩子入队;若其有右孩子,则将右孩子入队,返回②。
  • 示例:
    在这里插入图片描述

5、队列在计算机系统中的应用(填空)

  1. 解决主机与外部设备之间速度不匹配的问题。

    例子:主机和打印机之间速度不匹配的问题
    1、主机输出数据给打印机打印,输出数据的速度比打印数据的速度要快得多,由于速度不匹配,若直接把输出的数据送给打印机打印显然是不行的。
    2、解决的方法是设置一个打印数据缓冲区,主机把要打印输出的数据依次写入这个缓冲区,写满后就暂停输出,转去做其他的事情。打印机就从缓冲区中按照先进先出的原则依次取出数据并打印,打印完后再向主机发出请求。主机接到请求后再向缓冲区写入打印数据。这样做既保证了打印数据的正确,又使主机提高了效率。
    3、由此可见,打印数据缓冲区中所存储的数据就是一个队列。

  2. 解决由多用户引起的资源竞争问题。

    例子:CPU资源的竞争
    1、在一个带有多终端的计算机系统上,有多个用户需要CPU各自运行自己的程序,它们分别通过各自的终端向操作系统提出占用CPU的请求。
    2、操作系统通常按照每个请求在时间上的先后顺序,把它们排成一个队列,每次把CPU分配给队首请求的用户使用。当相应的程序运行结束或用完规定的时间间隔后,令其出队,再把CPU分配给新的队首请求的用户使用。这样既能满足每个用户的请求,又使CPU能够正常运行。

四、特殊矩阵的压缩存储(考得少)

1、数组(了解)

  1. 定义:由n(n≥1)个相同类型的数据元素构成的有限序列,每个数据元素称为一个数组元素,每个元素在n个线性关系中的序号称为该元素的下标,下标的取值范围称为数组的维界。
  2. 数组的存储结构:
    1. 一维数组
      在这里插入图片描述
    2. 二维数组
      • 按行优先:先行后列,先存储行号较小的元素,行号相等先存储列号较小的元素。
        在这里插入图片描述
      • 按列优先:
        在这里插入图片描述

2、矩阵的压缩矩阵(主要是坐标转换,没考过)

(1)对称矩阵

在这里插入图片描述

  • 元素a(i,j)在数组B中的下标k = 1 + 2 + ··· + (i - 1) + j - 1 = i(i - 1) / 2 + j - 1。(数组下标从0开始)
    • 元素下标之间的对应关系如下:
      在这里插入图片描述

五、稀疏矩阵

  1. 定义:矩阵中非零元素的个数 t ,相对矩阵元素的个数 s 来说非常少,即 s>>t 的矩阵称为稀疏矩阵。
  2. Q:常规方法存储浪费存储空间
    A:仅存储非零元素和它所在的行列。将非零元素及其相应的行和列构成一个三元组(行标、列标、值)。再按照某种规律(数组存储、十字链表法存储)存储这些三元组。
    在这里插入图片描述
  3. 稀疏矩阵压缩后失去随机存取特性。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值