【数据结构】考研真题攻克与重点知识点剖析 - 第 3 篇:栈、队列和数组

前言

  • 本文基础知识部分来自于b站:分享笔记的好人儿的思维导图与王道考研课程,感谢大佬的开源精神,习题来自老师划的重点以及考研真题。
  • 此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析,本人技术有限,最终数据清洗结果不够理想,相关****文章便没有发出。

(考研真题待更新)

欢迎订阅专栏:408直通车

请注意,本文中的部分内容来自网络搜集和个人实践,如有任何错误,请随时向我们提出批评和指正。本文仅供学习和交流使用,不涉及任何商业目的。如果因本文内容引发版权或侵权问题,请通过私信告知我们,我们将立即予以删除。

文章目录

  • 前言
  • 第三章 栈、队列和数组
      • 栈的概念
      • 栈的实现
        • 顺序栈
          • S.top == 0
        • 共享栈
        • 链栈
    • 队列
      • 队列的概念
      • 队列的实现
        • 队列的顺序存储结构
          • rear指向队尾元素
        • 队列的链式存储结构
        • 小结
      • 双端队列(挺喜欢考的考点)
      • 栈和队列有相同逻辑结构,线性结构
      • 合适与不合适做链队的链表,关键看能不能获取到首尾指针(带首尾的非循环或带尾的循环)
    • 栈和队列的应用
      • 栈的应用
        • 括号
        • 表达式求值
          • 中缀表达式转后缀表达式
          • 后缀表达式的计算
          • 中缀表达式转前缀表达式
          • 前缀表达式的计算
          • 中缀表达式的计算(用栈实现)
          • 其他
          • 小结
        • 递归
        • 小结
      • 队列的应用
    • 数组和特殊矩阵
      • 本节的题目计算都可以不记公式,直接代入推导
      • 数组
      • 特殊矩阵
    • 补充代码
      • 栈(数组模拟)
      • (循环)队列(数组模拟)
      • 单调栈
      • 单调队列
  • 考研真题
    • 408 - 2023

第三章 栈、队列和数组

在这里插入图片描述

栈的概念

  • 在这里插入图片描述

    • 限定仅在一端进行插入和删除操作的线性表,又称后进先出(LIFO)的线性表;
      允许插入删除的那一端叫栈顶(Top),不允许插入和删除的一端叫栈底(Bottom)

      • 特殊的线性表,后进先出(LIFO)在这里插入图片描述
    • 注意:n个不同元素进栈,出栈元素不同排序个数为(n个元素能构成多少种不同的二叉树)

    • 在这里插入图片描述
      在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

栈的实现

顺序栈
  • 栈的顺序存储结构

    • 顺序栈的基本结构在这里插入图片描述

      • 在这里插入图片描述

        • 利用一组地址连续的存储单元存放自栈底到栈顶的数据元素,同时设一个栈顶指针(Top)

        • 基础结构在这里插入图片描述

          • 栈顶指针,初始值:S.top = -1(若有元素,则指向栈顶元素S.data[S.top])在这里插入图片描述

          • 进栈:栈不满时,栈指针先+1,再送值到栈顶在这里插入图片描述

            • 出栈:栈非空时,先取栈顶元素值,再将栈顶指针-1在这里插入图片描述
          • 栈空条件:S.top == -1

            • 栈满条件:S.top == MaxSize-1

              • 栈长:S.top + 1
    • 顺序栈的基本操作

      • 初始化、判栈空、进栈、出栈、读栈顶元素(本质就是操作顺序表)在这里插入图片描述
S.top == 0

在这里插入图片描述
在这里插入图片描述

共享栈
  • 共享栈
    • 在这里插入图片描述
      在这里插入图片描述

    • 概念

      • 让两个顺序栈共享一个一维数组空间,将两个栈的栈底分别设置在共享空间的两端,两个栈顶向共享空间的中间延伸
    • 原则

      • 栈空判断:top0 = -1时0号栈为空,top1 = MaxSize时1号栈为空

      • 栈满判断:两个栈顶指针相邻(即top1-top0 == 1)时

      • 其他操作和顺序栈类似
        在这里插入图片描述

链栈

在这里插入图片描述

  • 栈的链式存储结构

  • 在这里插入图片描述

  • 采用单链表实现,并规定所有操作都是在单链表的表头进行在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 优点

    • 便于多个栈共享存储空间和提高效率,不存在栈满上溢的情况

队列

队列的概念

  • 在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    • 是一种操作受限的线性表,只允许在表的一端进行插入(队尾),另一端进行删除(队头)

      • 特殊的线性表,先进先出(FIFO)
    • 队头:删除元素的一端

      • 队尾:插入元素的一端
        在这里插入图片描述

队列的实现

队列的顺序存储结构
  • 队列的顺序存储结构
    • 在这里插入图片描述

      • 分配一块连续的存储单元存放队列元素,设两个指针

        • 队头指针front:指向队头元素
          队尾指针rear:指向队尾元素的下一个元素
      • 基础结构在这里插入图片描述

        • 初始状态(队空条件):Q.front == Q.rear == 0
          在这里插入图片描述

        • 进队操作:队不满时,先送值到队尾元素,再将队尾指针+1在这里插入图片描述
          在这里插入图片描述

        • 出队操作:队不空时,先取队头元素值,再将队头指针+1

      • 假溢出:在data数组依然存在空位置时,却已经满足队列满的条件(出栈的元素位置空闲)

    • 循环队列(解决假溢出问题)

      • 在这里插入图片描述
        在这里插入图片描述
        在这里插入图片描述

        • 概念

          • 把存储队列元素的表逻辑上视为一个环
        • 基本操作

          • 初始时:Q.front = Q.rear = 0

          • 队头指针+1:Q.front = (Q.front + 1) % MaxSize

          • 队尾指针+1:Q.rear = (Q.rear + 1) % MaxSize

          • 队列长度:(Q.rear + MaxSize - Q.front) % MaxSize

          • 队空:Q.front == Q.rear

        • 队满判断

          • 牺牲一个单元来区分队空和队满,即队头指针在队尾指针的下一位置作为队满标志在这里插入图片描述

            • 队满条件:(Q.rear + 1) % MaxSize == Q.front
          • 类型中增设表示元素个数的数据成员(int size)在这里插入图片描述

            • 队空:Q.size == 0

            • 队满:Q.size == MaxSize

          • 类型中增设tag数据成员,以区分是队满还是队空在这里插入图片描述

            • tag == 0时,若因删除导致Q.front == Q.rear,则队空

            • tag == 1时,若因插入导致Q.front == Q.rear,则队满

rear指向队尾元素

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
牺牲一个存储单元

  1. front在rear后两个位置,队满
  2. front在rear后一个位置,队满
    在这里插入图片描述
队列的链式存储结构
  • 队列的链式存储结构在这里插入图片描述
    • 在这里插入图片描述

      • 队列的链式表示时一个同时带有队头指针和队尾指针的单链表

      • 头指针指向队头结点,队尾指针指向队尾结点,当Q.front == NULL且Q.rear == NULL时,队列为空在这里插入图片描述
        在这里插入图片描述

      • 不存在队列满且溢出问题,适合于数据元素变动较大的情况在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

小结

在这里插入图片描述

双端队列(挺喜欢考的考点)

  • 概念

    • 双端队列是指允许两端都可以进行入队和出队操作的队列,其逻辑结构仍是线性表在这里插入图片描述
  • 分类在这里插入图片描述

    • 输出受限的双端队列:允许在一端进行插入和删除,但在另一端只允许插入的双端队列

    • 输入受限的双端队列:允许在一端进行插入和删除,但在另一端只允许删除的双端队列

栈和队列有相同逻辑结构,线性结构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

合适与不合适做链队的链表,关键看能不能获取到首尾指针(带首尾的非循环或带尾的循环)

  • 单链表实现队列,队头只能设置在链头(关注删除操作,需找到新队头)

栈和队列的应用

栈的应用

括号
  • 括号匹配在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    • 步骤

      • 初始设置一个空栈,顺序读入括号

      • 若右括号,则从栈中弹出一个符号,判断是否匹配

      • 若左括号,则压入栈中

    • 失败条件

      • 不匹配、结束后栈仍有元素、遇右括号栈为空
表达式求值

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

中缀表达式转后缀表达式
  • 从左到右遍历各元素

    • 若遇到操作数:直接加入后缀表达式

    • 遇到界限符:“(”直接入栈;“)”则依次弹出栈内运算符并加入后缀表达式,直到弹出“(”为止

    • 遇到运算符:依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式,若碰到“(”或栈空则停止,之后再把运算符入栈
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

后缀表达式的计算
  • 从左向右扫描元素,若扫描到操作数则压入栈,若扫描到运算符则弹出两个栈顶元素,执行运算将结构压回栈中
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

中缀表达式转前缀表达式
  • 同理但从右到左遍历,“(”和“)”与中缀转后缀的功能相反,最后结果依次翻转

在这里插入图片描述
在这里插入图片描述

前缀表达式的计算
  • 从右向左扫描元素,若扫描到操作数则压入栈,若扫描到运算符则弹出两个栈顶元素,执行运算将结构压回栈中

在这里插入图片描述
在这里插入图片描述

中缀表达式的计算(用栈实现)
  • 初始化操作数栈和运算符栈

  • 若扫描到操作数,压入操作数栈;若扫描到运算符或界限符,按“中缀转后缀”的逻辑压入运算符栈(可能弹出运算符,若弹出则将栈顶的两个操作数运算压回操作数栈)
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

其他
  • 其他:数制转换、八皇后问题、行编辑程序、函数调用、迷宫求解等
小结

在这里插入图片描述

递归

在这里插入图片描述

在这里插入图片描述

  • 概念

    • 若对象部分地包含自己,或用自己给自己定义,则称这个对象是递归的

    • 若一个过程直接或间接的调用自己,则这个过程是递归的

  • 分治的思想:必备条件

    • 能将一个问题转变成一个新问题,且两者的解法相同或类似,不同的仅是对象,且对象有变化规律

    • 可以通过上述转化将问题化简

    • 必须有一个明确的递归出口(递归边界)

  • 形式

    • 在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

在这里插入图片描述

小结

在这里插入图片描述

队列的应用

  • 脱机打印输出、解决多用户引起的资源竞争问题、广度优先遍历、网络电文传输按时间先后顺序依次进行等等

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数组和特殊矩阵

在这里插入图片描述

本节的题目计算都可以不记公式,直接代入推导

数组

  • 概念

    • 数组是由n个相同类型的数据元素构成的有限序列,每个元素在n个线性关系中的序号称为元素下标,下标取值范围称为数组的维界
  • 与线性表的关系

    • 数组是线性表的推广,一维数组可视为一个线性表,二维数组可以视为其元素也是定长线性表的线性表
  • 数组的存储结构

    • 数组的所有元素在内存中占用一段连续的存储空间

    • 一维数组在这里插入图片描述

      • 存储结构关系式:LOC(ai) = LOC(a0) + i × L (0 <= i < n,L是每个元素所占存储单元)
    • 多维数组在这里插入图片描述

      • 按行优先(一行行存储)

        • 存储结构关系式:LOC(ai,j) = LOC(a0,0) + [i × (h1 + l) + j] × L (二维数组:h1 × h2)在这里插入图片描述
      • 按列优先(一列列存储)

        • 存储结构关系式:LOC(ai,j) = LOC(a0,0) + [j × (h2 + l) + i] × L (二维数组:h1 × h2)在这里插入图片描述

特殊矩阵

  • 指具有许多相同矩阵元素或0元素,并且这些相同矩阵元素或0元素的分布有一定规律

  • 压缩矩阵

    • 找出特殊矩阵中值相同的矩阵元素的分布规律,把那些呈现分布规律的、多个值相同的元素只分配一个存储空间,对0元素不分配空间在这里插入图片描述
  • 对称矩阵

    • 概念

      • 若对一个n阶方阵中的任意元素a(i, j) = a(j, i),则称其为对称矩阵,可放在一维数组B[n(n+1)/2]中在这里插入图片描述
        在这里插入图片描述
        在这里插入图片描述
    • 存储位置计算公式在这里插入图片描述

  • 三角矩阵

    • 概念

      • (上/下)三角区的所有元素均为同一常量,其可压缩为存储完(下/上)三角区和主对角线上元素 + 存储常量一次
    • (下/上)三角矩阵元素下标对应关系

      • 下三角矩阵在这里插入图片描述
        在这里插入图片描述
        在这里插入图片描述

      • 上三角矩阵在这里插入图片描述

    • (下/上)三角矩阵在内存中的压缩存储形式

      • 下三角矩阵在这里插入图片描述

      • 上三角矩阵在这里插入图片描述

  • 三对角矩阵

    • 在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

      • 概念

        • 又称带状矩阵,除以对角线为中心的3条对角线区域外都为0
      • 压缩存储:将元素按行优先方式存放在一维数组B中,且a(i, j)与B[n]对应关系为:k = 2i + j - 3

  • 稀疏矩阵在这里插入图片描述

    • 概念

      • 矩阵中非0元素的个数t,相对矩阵元素的个数s来说非常少,即s>>t
    • 存储方式

      • 三元组(行标、列标、值)
        在这里插入图片描述

      • 十字链表法 在这里插入图片描述

    • 稀疏矩阵压缩存储后失去了随机存取的特性
      在这里插入图片描述
      在这里插入图片描述

补充代码

栈(数组模拟)

  • 对数组简单操作,略

(循环)队列(数组模拟)

  • 循环队列注意点:队满与队空条件需要有区别,即需要一个额外的元素空间判断队空与队满

void push_q(int x){
    if((tail + N + 1) % N != head){  //判断队满
        q[tail] = x;
        tail = (N + tail + 1) % N;  //队尾插入一个数据注意指针移动需要%N,对头类似:head=(N+head+1)%N;
    }
}
bool empty(){  //判断是否为空
    return head == tail;
}
void pop_q(){  //对头删去一个元素
    if(!empty())
        head = (N + head + 1) % N;
}
void query(){  //查询对头元素
    if(!empty())
        printf("%d\n",q[head]);
}

单调栈

  • 应用场景:求某个数左边第一个小于他的数;
    思路:在每次暴力从for循环的当前值,向左遍历找第一个小于数的O(n2)情况下进行优化;
    在向左遍历过程中删去无用的数(左边小于,但值大于),利用栈形成单调增大的序列,所求数即为栈顶;

  •   for(int i=0;i<n;i++){
          scanf("%d",&v);
          while(top&&s[top-1]>=v) top--;           //去除比当前数大但在左边的数
          if(!top) printf("-1 ");
          else printf("%d ",s[top-1]);                    //输出栈顶元素,即第一个小于当前数的数
          s[top++]=v;                                          //当前数压入栈中
      }
    

单调队列

  • 应用场景:滑动窗口中最小值,也可优化背包问题;
    思路:同理通过删去无用的数进行优化;
    (求滑动窗口中最小值)队列头保留最小的数,遍历数组,若队尾数大于遍历的数则不断删去队尾(同理无用的数),使得队列单调增,在遍历过程中,不断更新队头使得不超过滑动窗口。

  • for(int i=0;i<n;i++){
       if(l<r&&i-q[l]>len-1) l++;                       //移动对头使不超过滑动窗口,为了实现,q数组存下标
       while(l<r&&v[q[r-1]]>=v[i]) r--;              //弹出队尾无用数,因为会在队尾弹出不满足先进先出原则,事实上也不能叫单调队列
       q[r++]=i;                                                  //每次都入队一个
       if(i>=len-1) printf("%d ",v[q[l]]);
    }
    

考研真题

408 - 2023

(考研真题待更新)

上一篇:LabVIEW厂房漏水检测监控系统


下一篇:Mac的终端配置