资讯动态

循环队列front和rear初值怎么定?408真题带你避坑

发布时间:2026/9/8 7:10:45 来源:尧图企业网站定制
很多备考 408 的同学第一次做 2011 年第 3 题时会习惯性地套用教材里“循环队列初始化 front rear 0”的结论直接选 A结果答案却是 B。这其实不是粗心而是题目悄悄修改了 front 和 rear 的语义定义。今天我们就以这道经典真题为主线把循环队列的初值设定、指针指向、入队出队逻辑和常见误区一次性梳理清楚帮助你在考场上不再踩坑。1. 背景与核心概念1.1 循环队列要解决什么问题在数据结构中队列是一种先进先出的线性表。如果用数组实现普通顺序队列需要两个指针队头指针 front 和队尾指针 rear。入队时 rear 向后移动出队时 front 向后移动。这个过程看似简单却存在一个经典问题假溢出。假溢出指的是数组前段已经出队的位置明明空着但 rear 已经走到数组末尾继续入队会报“队列已满”。实际上数组前半部分还有大量空闲空间。为了解决这个问题循环队列应运而生。循环队列把数组在逻辑上看成一个首尾相接的环通过取模运算让 front 和 rear 在 0 到 n-1 之间循环移动。当 rear 到达数组末尾时下一跳回到数组头部从而复用之前出队释放的位置。这样队列的存储空间就能被反复利用这也是循环队列在操作系统、网络缓冲、消息队列等场景中被广泛使用的原因。1.2 为什么初值设定是 408 高频考点循环队列的初值看似简单实际很容易出错。因为 front 和 rear 的初始值并不是固定不变的它取决于题目对 front 和 rear 语义的定义。有的教材定义 front 指向队头元素rear 指向队尾元素的下一个位置有的题目则明确写成 rear 指向队尾元素。这两种定义下入队时指针的移动顺序不同初始值自然也不同。408 真题非常喜欢在这种“定义差异”上做文章。2011 年第 3 题就是典型代表题目明确说 rear 指向队尾元素导致很多同学套用默认的 front rear 0 模型后答错。理解这道题本质上就是理解“指针语义决定初值”这一核心思想。2. 2011 年第 3 题题目还原与考点定位2.1 原题题干与选项先来看这道考研 408 真题的常见回忆版本。题目描述已知循环队列存储在一维数组 A[0..n-1] 中且队列非空时front 和 rear 分别指向队头元素和队尾元素。若初始时队列为空且要求第一个进入队列的元素存储在 A[0] 处则初始时 front 和 rear 的值分别是 。选项A. 00B. 0n-1C. n-10D. n-1n-1标准答案是 B也就是 front 0rear n-1。2.2 考点定位与题目难度分析这道题属于数据结构中“栈和队列”章节具体考点是循环队列的存储结构、front 与 rear 的语义以及队列初始化顺序。从知识点本身来看循环队列属于基础内容但这道题的通过率和正确率并不高。原因是很多考生只记住了“循环队列初始化时 front rear 0”这个结论却忽略了题目给定了新的指针指向规则。换句话说这道题考查的不是记忆而是理解。它要求你根据 front 和 rear 的语义定义手动推导出初始值。这种考法比直接问“队空条件是什么”更灵活也更容易拉开分数差距。2.3 网上争论的焦点每年复习 408 时这道题都会被反复拿出来讨论最常见的争论是为什么很多教材说循环队列初始化时 front 和 rear 都为 0而这道题答案却是 0 和 n-1原因在于教材默认的模型是“rear 指向队尾元素的下一个位置”而入队顺序是“先存数据再移动 rear”。而这道题将 rear 定义为“指向队尾元素”入队时为了保持这个语义不变必须先移动 rear再存入新元素。如果 rear 已经指向队尾元素插入新元素时就必须先让 rear 指向下一个空位否则新元素会直接覆盖旧队尾。因此必须先移动 rear 再写入。这一差别决定了初值。3. 循环队列前置知识front、rear 的两种定义模型3.1 模型 Arear 指向队尾元素的下一个位置这是最经典的教材模型。在这种模型中front 指向队头元素rear 指向队尾元素的下一个位置初始化时通常取 front rear 0入队操作是“先写入再移动 rear”。用数组下标表示假设数组大小为 M入队过程为A[rear] x; rear (rear 1) % M;出队过程为x A[front]; front (front 1) % M;在这种模型下队空条件是 front rear。如果采用牺牲一个存储单元的方式来区分队空和队满那么队满条件是(rear 1) % M front队满时数组中最多存储 M-1 个元素。队列长度公式为(rear - front M) % M这个模型最大的优点是逻辑清晰判断队空、队满、求长度都非常方便因此绝大多数教材默认使用这种定义。3.2 模型 Brear 指向队尾元素本身2011 年第 3 题采用的则是另一种模型front 指向队头元素rear 指向队尾元素入队操作是“先移动 rear再写入”。数组大小为 M 时入队过程为rear (rear 1) % M; A[rear] x;出队过程依然是x A[front]; front (front 1) % M;在这种模型下如果要求第一个入队元素存储在 A[0] 处那么初始值必须特殊设置。因为第一次入队时 rear 要先加 1所以要让 rear 加 1 后等于 0初始 rear 只能是 M-1。front 不需要移动所以初始 front 为 0。另外需要注意模型 B 下不能直接用 front rear 判断队空。因为当队列中恰好只有一个元素时front 和 rear 也指向同一个位置。要准确判断队空、队满通常要借助计数器 count 或标志位 tag。3.3 两种模型对比表下面用表格把两种模型的区别总结清楚方便复习时对照。对比项模型 A模型 Brear 语义指向队尾元素的下一个位置指向队尾元素入队顺序先写入再移动 rear先移动 rear再写入常见初始值要求第一个元素在 A[0]front 0rear 0front 0rear n-1队空条件front rear需要额外标志count/tag队满条件牺牲一个存储单元(rear 1) % M front(rear 1) % M front但需配合额外标志队列长度公式(rear - front M) % M非空时 (rear - front M) % M 1推荐用计数器4. 本题详细推导答案为什么是 B4.1 根据 rear 定义反推 rear 初值题目已经明确队列非空时 rear 指向队尾元素。这意味着在入队操作完成后rear 必须恰好指向新插入的元素。为了满足这个语义插入新元素时rear 不能还指向旧队尾不动。它必须先移动到下一个空位再让新元素存进去。因此入队过程为rear (rear 1) % n; A[rear] x;现在题目要求第一个进入队列的元素存储在 A[0] 处。第一次入队时我们希望执行完 rear (rear 1) % n 之后rear 变为 0。也就是说(rear 1) % n 0在 0 到 n-1 的范围内满足这个条件的初始 rear 只能是 n-1。如果初始 rear 0那么第一次入队时 rear 会先变成 1第一个元素就会被存到 A[1] 而不是 A[0]这与题目要求矛盾。4.2 根据 front 定义确定 front 初值再看 front。题目说队列非空时 front 指向队头元素。第一个元素入队后它既是队尾元素也是队头元素。由于第一个元素存储在 A[0] 中所以第一个元素入队后front 必须等于 0才能满足“front 指向队头元素”的定义。入队操作不会改变 frontfront 只有在出队时才会向后移动。因此要让第一个元素入队后 front 恰好为 0初始 front 就必须是 0。从这个角度看front 0 并不表示“A[0] 中已经有元素”而是表示“队列为空时预先设定好将来第一个队头元素出现时要指向的位置”。这是一种逻辑上的预留。4.3 错误选项逐个排除A. 00rear 初始为 0第一次入队后 rear 变为 1第一个元素会存到 A[1]不符合题意。C. n-10rear 初始为 0 会导致第一个元素存到 A[1]front 初始为 n-1 则无法在第一个元素入队后指向队头 A[0]。D. n-1n-1rear 初始为 n-1 正确但 front 初始为 n-1第一个元素入队后 front 仍然指向 A[n-1]无法指向 A[0]。因此只有 B 选项同时满足“第一个元素存入 A[0]”和“front、rear 的语义定义”两个要求。5. 为什么不是 0,0常见误区深入剖析5.1 “0,0”在哪种定义下成立很多资料上写“循环队列初始化时 front rear 0”这本身并没有错但它默认采用的是模型 A也就是 rear 指向队尾元素的下一个位置。在模型 A 中初始化 front rear 0 后第一个元素入队时先执行 A[0] x再执行 rear (rear 1) % n此时 rear 变成 1。第一个元素确实存放在 A[0] 中。正是因为这个结论太常见导致很多考生看到“循环队列”就直接套用 front rear 0忽略了题目已经改变 rear 的语义。5.2 入队顺序的差别决定初值不同我们用 n 5 的数组举例对比两种模型的第一次入队过程。模型 Afront 0rear 0入队元素 10A[0] 10rear (0 1) % 5 1最终 front 0rear 1第一个元素在 A[0]。模型 Bfront 0rear 4入队元素 10rear (4 1) % 5 0A[0] 10最终 front 0rear 0第一个元素在 A[0]。可以看到虽然两种模型最终第一个元素都放到了 A[0]但 rear 的初值和入队后 rear 的最终值都不同。题目要求 rear 指向队尾元素所以入队后 rear 应该等于 0指向 A[0] 中的元素这与模型 B 完全一致。5.3 做题时如何避开思维惯性遇到循环队列初始化题最忌讳直接背结论。建议做题时按以下顺序思考先读题干明确 front 和 rear 分别指向什么写出入队操作的执行顺序假设第一个元素入队手动推一遍指针变化根据目标存储位置反推初始值。只要在草稿纸上画一个环形数组把 front 和 rear 的初始位置标出来再模拟一次入队过程这类题基本不会出错。6. 用 C 语言验证 2011 年第 3 题的初值逻辑6.1 一句话模拟第一个元素到底存到哪先用一段最简短的 C 语言代码验证核心逻辑。这里 n 8数组大小也是 8采用模型 B 的入队顺序。#include stdio.h #define N 8 int main() { int A[N]; int front 0; // 空队列时 front 指向将来队头元素的位置 int rear N - 1; // 空队列时 rear 初始化为最后一个位置 // 模拟第一个元素 10 入队 rear (rear 1) % N; A[rear] 10; printf(第一个元素存入: A[%d]\n, rear); printf(入队后 front %d, rear %d\n, front, rear); return 0; }运行结果第一个元素存入: A[0] 入队后 front 0, rear 0这段代码直接验证了当 rear 初始为 n-1 时第一个入队元素会先让 rear 变成 0然后存入 A[0]。6.2 完整循环队列实现带计数器前面的模拟只演示了第一次入队。为了更完整地展示整个循环队列的运行过程下面给出一个带计数器的循环队列完整实现。这里使用 count 记录元素个数从而准确区分队空和队满避免模型 B 下 front rear 无法判断队列状态的尴尬。这个实现只是为了验证初值逻辑考试中采用哪种方式判断队空、队满需要以题目说明为准。#include stdio.h #include stdbool.h #define MAX_SIZE 5 typedef struct { int data[MAX_SIZE]; int front; int rear; int count; } CircularQueue; void initQueue(CircularQueue *q) { q-front 0; q-rear MAX_SIZE - 1; q-count 0; } bool isEmpty(CircularQueue *q) { return q-count 0; } bool isFull(CircularQueue *q) { return q-count MAX_SIZE; } bool enQueue(CircularQueue *q, int value) { if (isFull(q)) { return false; } q-rear (q-rear 1) % MAX_SIZE; q-data[q-rear] value; q-count; return true; } bool deQueue(CircularQueue *q, int *value) { if (isEmpty(q)) { return false; } *value q-data[q-front]; q-front (q-front 1) % MAX_SIZE; q-count--; return true; } void printQueue(CircularQueue *q) { if (isEmpty(q)) { printf(队列为空\n); return; } int index q-front; for (int i 0; i q-count; i) { printf(A[%d]%d, index, q-data[index]); if (i q-count - 1) { printf( - ); } index (index 1) % MAX_SIZE; } printf(\n); } int main() { CircularQueue q; initQueue(q); printf(初始化: front%d, rear%d, count%d\n, q.front, q.rear, q.count); enQueue(q, 10); printf(入队10后: ); printQueue(q); printf(front%d, rear%d, count%d\n, q.front, q.rear, q.count); enQueue(q, 20); enQueue(q, 30); enQueue(q, 40); printf(继续入队20/30/40后: ); printQueue(q); printf(front%d, rear%d, count%d\n, q.front, q.rear, q.count); int value; deQueue(q, value); printf(出队一次取出 %d 后: , value); printQueue(q); printf(front%d, rear%d, count%d\n, q.front, q.rear, q.count); enQueue(q, 50); printf(再入队50后: ); printQueue(q); printf(front%d, rear%d, count%d\n, q.front, q.rear, q.count); return 0; }6.3 运行结果分析程序运行结果如下初始化: front0, rear4, count0 入队10后: A[0]10 front0, rear0, count1 继续入队20/30/40后: A[0]10 - A[1]20 - A[2]30 - A[3]40 front0, rear3, count4 出队一次取出 10 后: A[1]20 - A[2]30 - A[3]40 front1, rear3, count3 再入队50后: A[1]20 - A[2]30 - A[3]40 - A[4]50 front1, rear4, count4结合运行结果可以看到第一次入队后rear 从初始的 4 变成 0第一个元素成功存到 A[0]front 全程没有因为入队而改变它始终指向队头元素当队列中恰有一个元素时front 和 rear 都等于 0仅靠这两个变量无法判断空满因此代码中使用了 count 计数器。这个完整的实现可以帮助你直观理解模型 B 下初值设置的意义也解释了为什么实际工程中常用计数器或标志位来管理循环队列状态。7. 举一反三循环队列初值设定的通用分析法7.1 推导三步法面对循环队列初始化题目推荐使用以下三步法第一步确认 front 和 rear 的语义。是“指向队头元素”还是“指向队头元素的前一个位置”是“指向队尾元素”还是“指向队尾元素的下一个位置”第二步确认第一个入队元素的目标位置。题目通常会明确说第一个元素要存储在 A[0]或者要求你根据 front 的定义反推。第三步模拟第一次入队。先按照 rear 的语义写出入队代码再看第一次入队后 front 应该指向什么位置据此反推两个指针的初始值。这三种信息全部确定后初值自然就出来了不需要死记硬背。7.2 变式一rear 指向队尾元素的下一个位置如果题目改成“循环队列存储在一维数组 A[0..n-1] 中队列非空时 front 指向队头元素rear 指向队尾元素的下一个位置要求第一个进入队列的元素存储在 A[0] 处。”这其实就是模型 A。入队顺序是A[rear] x; rear (rear 1) % n;第一个元素写入时直接使用 A[0]所以初始 rear 0。front 依然在第一个元素入队后保持不变因此初始 front 0。最终答案是 front 0rear 0。很多教材中“front rear 0”的结论就适用于这种模型。7.3 变式二front 指向队头元素的前一个位置再举一个更有挑战性的变式。如果题目改成“循环队列存储在一维数组 A[0..n-1] 中队列非空时 front 指向队头元素的前一个位置rear 指向队尾元素要求第一个进入队列的元素存储在 A[0] 处。”首先分析入队。rear 指向队尾元素所以入队时依然要先移动 rear 再写入rear (rear 1) % n; A[rear] x;第一个元素要存到 A[0]因此初始 rear 必须为 n-1。再来分析 front。front 指向队头元素的前一个位置。第一个元素入队后它位于 A[0]所以 front 应该指向 A[0] 在逻辑环上的前一个位置也就是 A[n-1]。由于入队过程不会改变 front因此初始 front 必须是 n-1。最终答案是 front n-1rear n-1。这个变式告诉我们front 和 rear 的初始值不一定都是 0要严格根据题目定义和第一个元素的落点来推导。7.4 快速验证方法无论什么变式都可以在草稿纸上画一个环形数组来验证。以 n 4 为例画 4 个格子下标为 0、1、2、3首尾相连把 front 和 rear 的初始位置标上去模拟一次入队看第一个元素是否存入目标位置模拟一次出队看 front 是否能正确移动到队头位置。这种画图法虽然原始却是考试时最不容易出错的方法。考场上如果遇到没见过的定义不要慌画图推一遍往往比背结论更稳妥。8. 常见疑问与复习排错清单8.1 高频疑问对照表很多同学在复习循环队列时会有相似的疑问下面用表格整理几种常见情况问题现象常见原因解决思路一看到循环队列就默认 front rear 0混淆了两种 rear 定义模型先读题干确认 rear 指向队尾元素还是队尾元素的下一个位置选 A00套用“先存后移”的模型 A 推导模型 B若 rear 指向队尾元素入队时先移动 rear再写入不理解第一个元素入队后 front 为什么不变入队操作只修改 rearfront 只有在出队时才移动画出入队前后状态图就能看清用 (rear 1) % n front 判满时出现误判模型 B 初始化时 front 和 rear 相邻空状态也会满足该表达式使用计数器 count 或标志位 tag 区分空满队列长度公式记不住长度公式依赖 rear 语义模型 A 用 (rear - front n) % n模型 B 带计数器时直接用 count能写代码但做不对选择题缺少针对定义的推导训练每道题都先画图再推导不要凭经验和记忆选答案8.2 循环队列复习建议数据结构复习不能只看不练循环队列更是如此。建议按下面步骤进行第一步把教材中循环队列的入队、出队、判空、判满、求长度五种操作全部手写一遍。不要直接抄代码而是理解每一句的作用。第二步在草稿纸上模拟至少三组不同初值下的入队出队过程。比如 front 0、rear 0front 0、rear n-1front n-1、rear n-1分别记录第一次入队后指针的变化。第三步把 2011 年第 3 题和它的变式整理到错题本上旁边写上“指针语义决定入队顺序入队顺序决定初始值”这句话。第四步做历年 408 真题时把循环队列相关题目集中归类总结命题人喜欢在哪些地方设置陷阱。9. 总结与进一步学习方向通过 2011 年第 3 题我们需要掌握的核心能力是不要背初始值而是根据 front 和 rear 的语义定义结合第一次入队的目标位置反向推导指针初值。这道题的核心链条是题干定义 rear 指向队尾元素入队时要先移动 rear 再写入第一个元素要存到 A[0]所以初始 rear n-1第一个元素入队后 front 要指向 A[0]所以初始 front 0。把这条链条想清楚以后无论题目改成“rear 指向队尾元素的下一个位置”还是“front 指向队头元素的前一个位置”你都能快速推出答案。下一步可以继续复习顺序队列和链队列的基本操作双端队列、优先队列的特性队列在树的层序遍历、图的广度优先搜索中的应用循环队列中数组下标计算、队列长度计算等综合题目。循环队列是 408 数据结构中性价比很高的考点一道选择题往往只需要画图推演 30 秒就能得出答案。考场上遇到这类题先花 10 秒确认指针定义再动手推导基本不会失分。希望这篇解析能帮你把这道经典真题彻底吃透。如果觉得有收获可以收藏备用复习到队列部分时再拿出来对照。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价