【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 秒内选出来吗?
循环队列
Q的front指向队头元素,rear指向队尾元素的下一个位置 ,MAXSIZE为数组容量,则队满条件是( )。A.
(Q.rear + 1) % MAXSIZE == Q.frontB.
Q.rear == Q.frontC.
Q.rear + 1 == Q.frontD.
Q.rear == Q.front + 1
如果你犹豫了,或者分不清 front 和 rear 指向哪,那这篇就是为你写的。
队列和栈一样,是 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 普通顺序队列的"假溢出"
普通顺序队列用数组存元素,front 和 rear 一直往后走:
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 出队后,1 和 2 在队列中,1 在 2 前面(因为只能一端入队),所以不可能先出 1 再出 2。
6.3 双端队列的快速判断
对于输入受限双端队列,合法出队序列的充要条件:
不存在三个下标
i < j < k,使得出队序列中a[k] < a[i] < a[j]。
这和栈的出栈序列判断类似,但双端队列更灵活。
七、真题演练
7.1 循环队列判满
题目:
循环队列 Q 的 front 指向队头元素,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 循环队列元素个数
题目:
循环队列 Q 的 front 指向队头元素,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,3、3,2,1、2,3,1、2,1,3、1,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、计算机考研、算法
分类:数据结构与算法
如果这篇对你有帮助,欢迎点赞、收藏、评论。你的支持是我持续更新的动力。