考点频率 :★★★★★(数据结构必考,选择题每年至少1题,尤其爱考判空/判满条件)
难度 :⭐⭐⭐
建议:重点理解循环队列解决"假溢出"的原理,掌握判空、判满、元素个数三个公式
1️⃣ 为什么需要循环队列?
上一篇文章我们讲了顺序队列(数组实现)。它有一个严重的问题:假溢出(False Overflow)。
假溢出的产生过程:
- 初始状态:
front = rear = 0,队列为空 - 入队 A、B、C、D:
rear移动到 4 - 出队 A、B:
front移动到 2 - 此时数组前两个位置(0和1)已经空闲,但
rear已经在 4,无法再入队新元素
明明数组前面还有空闲空间,却无法使用------这就是"假溢出"。
解决方案 :把数组的首尾逻辑上连接起来 ,形成一个环形。当 rear 到达数组末尾时,下一步就绕回到数组开头------这就是循环队列(Circular Queue)。
2️⃣ 循环队列的核心约定
循环队列使用两个指针:
front:指向队头元素的位置rear:指向队尾元素的下一个位置(即下一个入队的位置)
三个核心公式(必背):
| 操作 | 公式 |
|---|---|
| 判空 | front == rear |
| 判满 | (rear + 1) % MAXSIZE == front |
| 元素个数 | (rear - front + MAXSIZE) % MAXSIZE |
⚠️ 注意 :循环队列中,为了区分"空"和"满",我们牺牲一个存储单元 ------当
(rear+1) % MAXSIZE == front时判满,此时实际上还有一个空位没有放数据(即该位置不存储元素,仅作为"满"的判定标记,保证front == rear只代表空)。这是最常见的实现方式,考试也默认采用这种约定。
3️⃣ 为什么牺牲一个空间?
如果不牺牲空间,front == rear 可能代表"空"也可能代表"满":
| 情况 | front |
rear |
含义 |
|---|---|---|---|
| 空队列 | 0 | 0 | front == rear |
| 满队列 | 0 | 0 | front == rear(绕了一圈回到原点) |
同一个条件无法区分两种情况。所以牺牲一个空间 ,让"满"的条件变成 (rear+1) % MAXSIZE == front,这样就和"空"的条件区分开了。
4️⃣ 循环队列的基本操作
4.1 入队(Enqueue)
c
int Enqueue(SeqQueue* q, int x) {
if ((q->rear + 1) % MAXSIZE == q->front) {
return -1; // 队列已满
}
q->data[q->rear] = x;
q->rear = (q->rear + 1) % MAXSIZE;
return 0;
}
4.2 出队(Dequeue)
c
int Dequeue(SeqQueue* q, int* x) {
if (q->front == q->rear) {
return -1; // 队列为空
}
*x = q->data[q->front];
q->front = (q->front + 1) % MAXSIZE;
return 0;
}
4.3 元素个数计算
c
int GetLength(SeqQueue* q) {
return (q->rear - q->front + MAXSIZE) % MAXSIZE;
}
5️⃣ 例题详解
例题1 :某循环队列的数组大小为 6,front = 2,rear = 5,则队列中的元素个数为( )。
A. 2
B. 3
C. 4
D. 5
解析:
- 元素个数 =
(rear - front + MAXSIZE) % MAXSIZE - =
(5 - 2 + 6) % 6 = 9 % 6 = 3 - 选 B。
例题2 :某循环队列的数组大小为 8,若 front = 3,则 rear 为多少时表示队列已满?
A. 2
B. 3
C. 4
D. 6
解析:
- 判满条件:
(rear + 1) % 8 == front - 代入
front = 3:(rear + 1) % 8 == 3 - 满足条件的
rear = 2(因为(2+1)%8=3) - 选 A。
例题3 (变式):某循环队列的数组大小为 5,当前 front = 3,rear = 2,再入队一个元素后,front 和 rear 的值分别是多少?
解析:
- 当前元素个数 =
(2 - 3 + 5) % 5 = 4 % 5 = 4 - 数组大小为5,牺牲1个空间,最多存4个元素
- 当前已经存了4个,队列已满,无法入队
- 入队失败,
front和rear不变:front=3,rear=2
答案 :无法入队,front=3,rear=2
6️⃣ 三种处理"满/空"的方式
除了"牺牲一个空间"外,还有其他方式可以区分满和空。考试偶尔会涉及:
| 方案 | 判空 | 判满 | 说明 |
|---|---|---|---|
| 牺牲一个空间 | front == rear |
(rear+1)%MAXSIZE == front |
最常见,考试默认方案 |
| 增加 size 变量 | size == 0 |
size == MAXSIZE |
多一个变量记录元素个数,无需牺牲空间 |
| 增加 flag 变量 | flag == 0 && front==rear |
flag == 1 && front==rear |
用 flag 标记最后一次操作是入队还是出队 |
考试提示 :如果题目没有特别说明,默认采用牺牲一个空间 的方案。如果题目说"队列中有一个size变量记录元素个数",则判空判满条件要用
size。
7️⃣ 记忆口诀
循环队列首尾连,假溢出问题不再现。
front == rear为空,(rear+1)%max == front为满。元素个数公式记:
(rear - front + max) % max。
8️⃣ 小测验(评论区对答案)
某循环队列的数组大小为 10,当前
front = 6,rear = 4,队列中元素个数为( )。再入队两个元素后,front和rear的值分别是多少?A. 8;
front=6,rear=6B. 8;
front=6,rear=8C. 6;
front=6,rear=8D. 6;
front=6,rear=6
🔔 本专栏日更,点击头像 → 专栏《软考中级高频考点》订阅,第一时间接收新内容
#软考中级 #软件设计师 #循环队列 #队列 #数据结构 #软考备考