Skip to content

循环队列

为什么需要循环队列

普通顺序队列用数组实现时,随着反复入队、出队,frontrear 指针不断后移,即使数组前端已有空闲位置也无法再利用,产生假溢出现象:

已出队(浪费)  有效元素     rear 已到末尾 → 报满
 [  ][  ]      [a3][a4][a5]
  ↑front                ↑rear

循环队列的思路:把数组在逻辑上首尾相连,形成一个"环"。当指针到达数组末尾时,通过取模运算让它回到数组开头,从而复用前端空闲空间,彻底解决假溢出问题。

核心思想

循环队列使用长度为 MaxSize 的数组 data,维护两个指针:

  • front:指向队头元素
  • rear:指向队尾元素的下一个位置(即下一个入队位置)

指针移动的核心公式(取模实现"循环"):

front = (front + 1) % MaxSize   // 出队后 front 前进
rear  = (rear  + 1) % MaxSize   // 入队后 rear 前进

初始状态:front = rear = 0

基本结构定义:

c
#define MaxSize 10

typedef struct {
    int data[MaxSize];
    int front, rear;
} SqQueue;

交互可视化

通过下方的交互动画,你可以逐步观察循环队列的执行过程:

加载可视化中...

操作详解

入队操作

将新元素放入 rear 指向的位置,然后 rear 后移一位(取模)。

关键步骤:

  1. 判断队列是否已满
  2. 将元素存入 data[rear]
  3. rear = (rear + 1) % MaxSize
c
bool EnQueue(SqQueue *Q, int x) {
    if ((Q->rear + 1) % MaxSize == Q->front)
        return false;           // 队满
    Q->data[Q->rear] = x;
    Q->rear = (Q->rear + 1) % MaxSize;
    return true;
}

出队操作

取出 front 指向的元素,然后 front 后移一位(取模)。

关键步骤:

  1. 判断队列是否为空
  2. 取出 data[front] 的值
  3. front = (front + 1) % MaxSize
c
bool DeQueue(SqQueue *Q, int *x) {
    if (Q->front == Q->rear)
        return false;           // 队空
    *x = Q->data[Q->front];
    Q->front = (Q->front + 1) % MaxSize;
    return true;
}

判满与判空

循环队列中 front == rear 时可能是队空也可能是队满,必须加以区分。408 常考以下三种方案:

方案一:牺牲一个存储单元(最常用) ⭐

约定 rear 的下一个位置是 front 时为满,即始终保留一个空位不存数据。

条件表达式
队空front == rear
队满(rear + 1) % MaxSize == front
元素个数(rear - front + MaxSize) % MaxSize

此时队列最多存放 MaxSize - 1 个元素。

方案二:增设 size 计数器

额外维护一个 size 变量,入队 size++,出队 size--

条件表达式
队空size == 0
队满size == MaxSize
元素个数size

此时队列可用满全部 MaxSize 个位置。

方案三:增设 tag 标志位

tag 记录最近一次操作类型:入队置 tag = 1,出队置 tag = 0

条件表达式
队空front == rear && tag == 0
队满front == rear && tag == 1

逻辑:只有连续入队才可能导致满,只有连续出队才可能导致空。

⭐ 元素个数公式(三种方案通用):(rear - front + MaxSize) % MaxSize。当采用方案二/三使队列存满时,该公式结果为 0 需特判,因此考试中最常搭配方案一使用。

复杂度分析

操作时间复杂度说明
入队O(1)直接在 rear 位置写入
出队O(1)直接取 front 位置元素
获取队头O(1)访问 data[front]
判空/判满O(1)指针比较或计数器判断

空间复杂度:O(1),所有操作只需常数级辅助空间。

考研高频考点

  • ⭐ 判满判空三种方案的区别与表达式(选择题/简答题高频)
  • ⭐ 元素个数公式 (rear - front + MaxSize) % MaxSize(填空题必考)
  • ⭐ 给定 front、rear、MaxSize,求队列长度或判断状态(计算题)
  • ⭐ 循环队列解决假溢出的原理(概念题)
  • 入队/出队操作的代码填空(算法填空题)
  • rearfront 的含义约定(指向队尾元素 vs 队尾下一个位置,不同教材有差异)