【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清

【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清

专栏导航 :本篇是《408数据结构:C++手写实现 + 图解 + 真题》第 08 篇。

上一篇【408数据结构 07】栈:408每年必考,这3个坑90%的人会踩

下一篇【408数据结构 09】栈和队列应用:括号匹配、表达式求值、递归

### 文章目录

  • [【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [@toc](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [先做个自测](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [一、队列到底是什么?一句话:先进先出](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [二、408 怎么考队列?先看真题分布](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [三、顺序队列:为什么需要循环?](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [3.1 普通顺序队列的"假溢出"](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [3.2 循环队列图解](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [四、循环队列的三种判空判满方法(408 核心)](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [4.1 方法一:牺牲一个存储单元(最常考)](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [4.2 方法二:设置 size 变量](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [4.3 方法三:设置 tag 标志](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [五、链队列:用链表实现队列](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [六、双端队列:408 新宠](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [6.1 三种双端队列](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [6.2 408 常考问法](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [6.3 双端队列的快速判断](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [七、真题演练](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [7.1 循环队列判满](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [7.2 循环队列元素个数](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [7.3 链队列出队](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [7.4 双端队列](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [八、一句话记住队列](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)
  • [九、总结与下一篇预告](#文章目录 【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清 @[toc] 先做个自测 一、队列到底是什么?一句话:先进先出 二、408 怎么考队列?先看真题分布 三、顺序队列:为什么需要循环? 3.1 普通顺序队列的“假溢出” 3.2 循环队列图解 四、循环队列的三种判空判满方法(408 核心) 4.1 方法一:牺牲一个存储单元(最常考) 4.2 方法二:设置 size 变量 4.3 方法三:设置 tag 标志 五、链队列:用链表实现队列 六、双端队列:408 新宠 6.1 三种双端队列 6.2 408 常考问法 6.3 双端队列的快速判断 七、真题演练 7.1 循环队列判满 7.2 循环队列元素个数 7.3 链队列出队 7.4 双端队列 八、一句话记住队列 九、总结与下一篇预告)

先做个自测

下面这道题,你能 10 秒内选出来吗?

循环队列 Qfront 指向队头元素,rear 指向队尾元素的下一个位置MAXSIZE 为数组容量,则队满条件是( )。

A. (Q.rear + 1) % MAXSIZE == Q.front

B. Q.rear == Q.front

C. Q.rear + 1 == Q.front

D. Q.rear == Q.front + 1

如果你犹豫了,或者分不清 frontrear 指向哪,那这篇就是为你写的。

队列和栈一样,是 408 选择题的常驻嘉宾

栈考出栈序列,队列考判空判满

而且队列的判空判满有三种写法,考试换一种你就容易翻车。

今天我们把队列的考点、代码、易错点一次讲透。


一、队列到底是什么?一句话:先进先出

队列(Queue)是只允许在一端插入、另一端删除的线性表。

  • 允许插入的一端叫队尾(rear)
  • 允许删除的一端叫队头(front)

生活里的例子:

  • 排队买票:先来的先买,后来的排后面。
  • 打印机任务:先提交的先打印。
  • 消息队列:先发送的先处理。

核心规则:

先进先出(FIFO, First In First Out)

图解:

text 复制代码
        队头 front                      队尾 rear
          |                                |
          v                                v
        +-----+-----+-----+-----+-----+
出队 <- |  1  |  2  |  3  |  4  |  5  | <- 入队
        +-----+-----+-----+-----+-----+

入队叫 enqueue,出队叫 dequeue


二、408 怎么考队列?先看真题分布

队列在 408 中的考法非常固定:

考法 出现频率 典型问法
循环队列判空判满 ★★★★★ 给 front/rear 定义,问判空判满条件
循环队列元素个数 ★★★★★ 问队列中当前有多少元素
顺序队列假溢出 ★★★★ 为什么需要循环队列
链队列 ★★★ 链队列的插入删除
双端队列 ★★★★ 输入受限/输出受限双端队列
队列应用 ★★★★ 层序遍历、BFS、缓冲区

重点:循环队列判空判满、元素个数计算、双端队列,这三个几乎年年考。


三、顺序队列:为什么需要循环?

3.1 普通顺序队列的"假溢出"

普通顺序队列用数组存元素,frontrear 一直往后走:

text 复制代码
初始:
front = 0, rear = 0
+-----+-----+-----+-----+-----+
|     |     |     |     |     |
+-----+-----+-----+-----+-----+
  0     1     2     3     4

入队 1, 2, 3, 4:
front = 0, rear = 4
+-----+-----+-----+-----+-----+
|  1  |  2  |  3  |  4  |     |
+-----+-----+-----+-----+-----+
  0     1     2     3     4

出队 1, 2:
front = 2, rear = 4
+-----+-----+-----+-----+-----+
|     |     |  3  |  4  |     |
+-----+-----+-----+-----+-----+
  0     1     2     3     4

再入队 5:
front = 2, rear = 5
+-----+-----+-----+-----+-----+
|     |     |  3  |  4  |  5  |
+-----+-----+-----+-----+-----+
  0     1     2     3     4

此时 rear == MAXSIZE,但数组前面还有空位!
这就是"假溢出"。

解决办法:让 rear 和 front 走到末尾后回到开头,形成循环队列。

3.2 循环队列图解

text 复制代码
MAXSIZE = 5

        front
          |
          v
        +-----+
     +--|  3  |--+
     |  +-----+  |
     |           |
+-----+       +-----+
|  5  |       |  4  |
+-----+       +-----+
     |           |
     |  +-----+  |
     +--|     |--+
        +-----+
          ^
          |
        rear

移动公式:

text 复制代码
front = (front + 1) % MAXSIZE
rear  = (rear + 1) % MAXSIZE

四、循环队列的三种判空判满方法(408 核心)

这是 408 最爱考的地方,必须分清

4.1 方法一:牺牲一个存储单元(最常考)

约定:

  • front 指向队头元素。
  • rear 指向队尾元素的下一个位置
  • 空出一个位置不用,用来区分空和满。

判空:

text 复制代码
front == rear

判满:

text 复制代码
(rear + 1) % MAXSIZE == front

元素个数:

text 复制代码
(rear - front + MAXSIZE) % MAXSIZE

图解:

text 复制代码
空队列:
front = rear = 0
+-----+-----+-----+-----+-----+
|     |     |     |     |     |
+-----+-----+-----+-----+-----+
  0     1     2     3     4
  ^
  |
front/rear

满队列(牺牲一个单元):
front = 0, rear = 4
+-----+-----+-----+-----+-----+
|  1  |  2  |  3  |  4  |     |  <- 位置4空着不用
+-----+-----+-----+-----+-----+
  0     1     2     3     4
  ^                       ^
  |                       |
front                   rear

代码:

cpp 复制代码
#define MAXSIZE 100

typedef int ElemType;

typedef struct {
    ElemType data[MAXSIZE];
    int front;
    int rear;
} SqQueue;

void InitQueue(SqQueue &Q) {
    Q.front = 0;
    Q.rear = 0;
}

bool QueueEmpty(SqQueue Q) {
    return Q.front == Q.rear;
}

bool QueueFull(SqQueue Q) {
    return (Q.rear + 1) % MAXSIZE == Q.front;
}

bool EnQueue(SqQueue &Q, ElemType x) {
    if (QueueFull(Q)) {
        return false;
    }
    Q.data[Q.rear] = x;
    Q.rear = (Q.rear + 1) % MAXSIZE;
    return true;
}

bool DeQueue(SqQueue &Q, ElemType &x) {
    if (QueueEmpty(Q)) {
        return false;
    }
    x = Q.data[Q.front];
    Q.front = (Q.front + 1) % MAXSIZE;
    return true;
}

int QueueLength(SqQueue Q) {
    return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

记忆口诀:

front 指队头,rear 指队尾下一个。

空:front == rear。

满:(rear + 1) % MAXSIZE == front。

个数:(rear - front + MAXSIZE) % MAXSIZE。

4.2 方法二:设置 size 变量

增加一个 size 变量记录元素个数。

  • 判空:size == 0
  • 判满:size == MAXSIZE
  • 元素个数:size
cpp 复制代码
typedef struct {
    ElemType data[MAXSIZE];
    int front;
    int rear;
    int size;
} SqQueue2;

这种方法最直观,但 408 更爱考方法一。

4.3 方法三:设置 tag 标志

增加一个 tag

  • tag = 0:最近一次是出队操作。

  • tag = 1:最近一次是入队操作。

  • 判空:front == rear && tag == 0

  • 判满:front == rear && tag == 1

cpp 复制代码
typedef struct {
    ElemType data[MAXSIZE];
    int front;
    int rear;
    int tag;
} SqQueue3;

三种方法对比:

方法 判空 判满 元素个数
牺牲一个单元 front == rear (rear+1)%MAXSIZE == front (rear-front+MAXSIZE)%MAXSIZE
设 size size == 0 size == MAXSIZE size
设 tag front==rear && tag==0 front==rear && tag==1 需另算

408 最常考方法一


五、链队列:用链表实现队列

链队列通常用带头结点的单链表

  • front 指向头结点。
  • rear 指向队尾结点。

图解:

text 复制代码
front                   rear
  |                       |
  v                       v
[头] -> [1] -> [2] -> [3] -> NULL
  • 入队:在 rear 后面插入新结点,rear 后移。
  • 出队:删除 front 的后继结点。

结构:

cpp 复制代码
typedef struct QNode {
    ElemType data;
    struct QNode *next;
} QNode, *QueuePtr;

typedef struct {
    QueuePtr front;
    QueuePtr rear;
} LinkQueue;

核心操作:

cpp 复制代码
// 初始化
void InitLinkQueue(LinkQueue &Q) {
    Q.front = Q.rear = new QNode;
    Q.front->next = nullptr;
}

// 判空
bool LinkQueueEmpty(LinkQueue Q) {
    return Q.front == Q.rear;
}

// 入队
void EnLinkQueue(LinkQueue &Q, ElemType x) {
    QNode *p = new QNode;
    p->data = x;
    p->next = nullptr;
    Q.rear->next = p;
    Q.rear = p;
}

// 出队
bool DeLinkQueue(LinkQueue &Q, ElemType &x) {
    if (LinkQueueEmpty(Q)) {
        return false;
    }
    QNode *p = Q.front->next;
    x = p->data;
    Q.front->next = p->next;
    if (Q.rear == p) {
        Q.rear = Q.front;  // 队列变空
    }
    delete p;
    return true;
}

链队列的坑:

出队时,如果删除的是最后一个结点,必须把 rear 重新指向头结点。

否则 rear 会变成野指针。

408 常考:

链队列出队时,什么情况下需要修改 rear 指针?

答:当出队的是队列中最后一个元素时。


六、双端队列:408 新宠

双端队列(Deque)允许两端都可以插入和删除

6.1 三种双端队列

类型 特点
普通双端队列 两端都可以入队和出队
输入受限双端队列 只允许一端插入,两端都可以删除
输出受限双端队列 只允许一端删除,两端都可以插入

图解:

text 复制代码
普通双端队列:
入队/出队 <-- [ | | | | ] --> 入队/出队

输入受限:
只允许一端入队 <-- [ | | | | ] --> 两端都能出队

输出受限:
两端都能入队 <-- [ | | | | ] --> 只允许一端出队

6.2 408 常考问法

输入受限双端队列,入队序列为 1, 2, 3, 4,哪些出队序列不可能?

这类题用模拟法,和栈的出栈序列类似。

例题:

输入受限双端队列(只允许一端入队,两端都可以出队),入队序列为 1, 2, 3, 4,则哪个出队序列不可能?

A. 1, 2, 3, 4

B. 4, 3, 2, 1

C. 2, 4, 3, 1

D. 3, 1, 2, 4

答案:D

解析:3, 1, 2, 4 中,3 出队后,12 在队列中,12 前面(因为只能一端入队),所以不可能先出 1 再出 2

6.3 双端队列的快速判断

对于输入受限双端队列,合法出队序列的充要条件:

不存在三个下标 i < j < k,使得出队序列中 a[k] < a[i] < a[j]

这和栈的出栈序列判断类似,但双端队列更灵活。


七、真题演练

7.1 循环队列判满

题目:

循环队列 Qfront 指向队头元素,rear 指向队尾元素的下一个位置,MAXSIZE 为数组容量,则队满条件是( )。

A. (Q.rear + 1) % MAXSIZE == Q.front

B. Q.rear == Q.front

C. Q.rear + 1 == Q.front

D. Q.rear == Q.front + 1

答案:A

7.2 循环队列元素个数

题目:

循环队列 Qfront 指向队头元素,rear 指向队尾元素的下一个位置,MAXSIZE 为数组容量,则队列中元素个数是( )。

A. Q.rear - Q.front

B. Q.rear - Q.front + MAXSIZE

C. (Q.rear - Q.front + MAXSIZE) % MAXSIZE

D. (Q.rear - Q.front) % MAXSIZE

答案:C

7.3 链队列出队

题目:

链队列出队时,什么情况下需要修改 rear 指针?

A. 队列为空时

B. 出队的是最后一个元素时

C. 出队的是第一个元素时

D. 任何时候都不需要

答案:B

7.4 双端队列

题目:

输入受限双端队列,入队序列为 1, 2, 3,则可能的出队序列有多少种?

A. 3

B. 4

C. 5

D. 6

答案:C

解析:可能的出队序列有:1,2,33,2,12,3,12,1,31,3,2,共 5 种。


八、一句话记住队列

队列先进先出,循环队列牺牲一个单元,空看 frontrear,满看 (rear+1)%MAXSIZEfront,个数看 (rear-front+MAXSIZE)%MAXSIZE,链队列出队最后一个要改 rear。


九、总结与下一篇预告

本篇讲了:

  • 队列的定义与先进先出特性。
  • 顺序队列的假溢出问题。
  • 循环队列的三种判空判满方法。
  • 循环队列元素个数计算。
  • 链队列的实现与出队坑点。
  • 双端队列的三种类型与判断方法。
  • 408 真题与易错点。

下一篇进入栈和队列的应用:

【408数据结构 09】栈和队列应用:括号匹配、表达式求值、递归

我会讲括号匹配、中缀转后缀、表达式求值、递归与栈的关系、层序遍历,配 408 真题和完整 C++ 代码。


专栏导航

  • 上一篇:【408数据结构 07】栈:408每年必考,这3个坑90%的人会踩
  • 下一篇:【408数据结构 09】栈和队列应用:括号匹配、表达式求值、递归
  • 专栏目录:《408数据结构:C++手写实现 + 图解 + 真题》

标签 :数据结构、C++、考研408、计算机考研、算法

分类:数据结构与算法

如果这篇对你有帮助,欢迎点赞、收藏、评论。你的支持是我持续更新的动力。

相关推荐
xiangyun611 小时前
【408数据结构 06】双链表、循环链表、静态链表
c语言·开发语言·数据结构·c++·算法
OKkankan2 小时前
LangChain 能力详解!:输出解析、RAG、向量数据库与 Retriever 检索器
数据结构·python·langchain·ai应用
蓝速科技2 小时前
便民服务大厅 AI 数字人一体机场景适配与落地指南丨蓝速科技
大数据·网络·数据结构·人工智能·自然语言处理·数据分析·运维开发
白远山2 小时前
家政服务家政社区派单实战:调度系统架构设计与实现指南
java·开发语言·小程序·架构·需求分析
302wanger3 小时前
推荐下我的两个AI信息源
算法
索尔~古德曼3 小时前
CF——错题的集合
算法
fpcc3 小时前
计算机原理—构建过程中的分段分析
c++
xxwxx__3 小时前
C++ AVL 树深度剖析:平衡二叉搜索树原理、源码与面试考点
数据结构·c++
SL_staff3 小时前
JVS-Logic:从页面配置工具到企业级业务逻辑中枢的技术演进
java·算法·全栈