【数据结构实战】C 语言实现静态顺序队列:从原理到完整可运行代码

1. 队列的顺序结构定义(静态数组版)
cpp 复制代码
#define MAXSIZE 100  // 队列最大容量
typedef int ElemType; // 队列元素类型,这里用int举例

// 顺序队列结构体定义
typedef struct {
    ElemType data[MAXSIZE]; // 存储队列元素的数组
    int front;              // 队头指针,指向队头元素
    int rear;               // 队尾指针,指向队尾元素的下一个位置
} Queue;

注释说明

  • MAXSIZE 限定队列最多能存的元素个数。
  • front 初始为 0,代表队头位置;rear 初始为 0,代表下一个入队元素要存放的位置。
  • front == rear 时队列为空。

2. 队列初始化
cpp 复制代码
// 初始化队列:将队头和队尾指针置为0
void initQueue(Queue *Q) {
    Q->front = 0; // 队头指针指向0
    Q->rear = 0;  // 队尾指针指向0
}

注释说明

  • 初始化后队列状态为空(front == rear)。
  • 传入指针是为了直接修改原队列结构体。

3. 判断队列是否为空
cpp 复制代码
// 判断队列是否为空:空返回1,非空返回0
int isEmpty(Queue *Q) {
    if (Q->front == Q->rear) { // 队头等于队尾,说明无元素
        printf("空的\n");
        return 1;
    } else {
        return 0;
    }
}

注释说明

  • 核心判断条件:front == rear 表示队列中没有元素。
  • 空队列时打印提示并返回 1,否则返回 0。

4. 入队操作(静态数组版)
cpp 复制代码
// 入队:将元素e插入队尾,成功返回1,失败返回0
int enqueue(Queue *Q, ElemType e) {
    if (Q->rear >= MAXSIZE) { // 队尾指针超出数组最大下标,队列满
        if (!queueFull(Q)) {  // 调用队列满处理函数(后续实现)
            return 0;
        }
    }
    Q->data[Q->rear] = e; // 将元素e存入队尾位置
    Q->rear++;            // 队尾指针后移
    return 1;             // 入队成功
}

注释说明

  • 先检查队尾是否越界(rear >= MAXSIZE),若越界则尝试处理队列满。
  • 未越界时,将元素存入data[rear],并让rear自增。
  • 成功入队返回 1,失败返回 0。

5. 出队操作
cpp 复制代码
// 出队:删除队头元素并返回,空队列返回0
ElemType dequeue(Queue *Q) {
    if (Q->front == Q->rear) { // 队列为空,无法出队
        printf("空的\n");
        return 0;
    }
    ElemType e = Q->data[Q->front]; // 取出队头元素
    Q->front++;                    // 队头指针后移
    return e;                      // 返回出队元素
}

注释说明

  • 先判断队列是否为空,为空则打印提示并返回 0。
  • 非空时,取出data[front]的值,让front自增,实现 "删除队头"。
  • 返回被出队的元素值。

6. 获取队头元素(不删除)
cpp 复制代码
// 获取队头元素:将队头元素存入*e,成功返回1,失败返回0
int getHead(Queue *Q, ElemType *e) {
    if (Q->front == Q->rear) { // 队列为空,无队头元素
        printf("空的\n");
        return 0;
    }
    *e = Q->data[Q->front]; // 将队头元素赋值给*e
    return 1;               // 获取成功
}

注释说明

  • 与出队不同,getHead 只读取data[front],不修改front指针。
  • 通过指针e带回队头元素值,避免函数返回值同时承载 "状态 + 数据" 的歧义。

7. 队列满处理(数据搬移)
cpp 复制代码
// 处理队列满:将有效数据搬移到数组开头,释放后面空间
int queueFull(Queue *Q) {
    if (Q->front > 0) { // 队头不在0位置,说明前面有空闲空间
        int step = Q->front; // 计算需要前移的步数
        // 遍历有效数据,将其向前移动step位
        for (int i = Q->front; i < Q->rear; ++i) {
            Q->data[i - step] = Q->data[i];
        }
        Q->front = 0;                // 队头重置为0
        Q->rear = Q->rear - step;    // 队尾同步前移
        return 1;                    // 处理成功
    } else {
        printf("真的满了\n"); // 队头已经是0,无空闲空间,队列真满
        return 0;
    }
}

注释说明

  • 静态数组队列会出现 "假溢出"(rear到末尾但front前有空位),此函数解决该问题。
  • [front, rear-1]的有效数据搬移到[0, rear-front-1],重置frontrear
  • front已经是 0,说明队列真满,无法处理。

8. 动态内存分配版队列定义
cpp 复制代码
// 动态分配版队列结构体
typedef struct {
    ElemType *data; // 指向动态分配的数组指针
    int front;       // 队头指针
    int rear;        // 队尾指针
} Queue;

// 动态初始化队列:返回队列指针
Queue* initQueue() {
    // 为队列结构体分配内存
    Queue *q = (Queue*)malloc(sizeof(Queue));
    // 为数据数组分配MAXSIZE个元素的内存
    q->data = (ElemType*)malloc(sizeof(ElemType) * MAXSIZE);
    q->front = 0; // 初始化队头
    q->rear = 0;  // 初始化队尾
    return q;      // 返回队列指针
}

注释说明

  • malloc动态分配数组空间,相比静态数组更灵活(可在运行时决定容量)。
  • initQueue 封装了队列创建和初始化的全过程,返回一个可用的队列指针。

二、完整可运行代码(含注释)

cpp 复制代码
#include <stdio.h>
#include <stdlib.h> // 用于malloc/free

#define MAXSIZE 100  // 队列最大容量
typedef int ElemType; // 队列元素类型

// 顺序队列结构体定义(动态版)
typedef struct {
    ElemType *data; // 动态数组指针
    int front;      // 队头指针
    int rear;       // 队尾指针
} Queue;

// 初始化队列(动态分配版)
Queue* initQueue() {
    Queue *q = (Queue*)malloc(sizeof(Queue));
    q->data = (ElemType*)malloc(sizeof(ElemType) * MAXSIZE);
    q->front = 0;
    q->rear = 0;
    return q;
}

// 判断队列是否为空
int isEmpty(Queue *Q) {
    return (Q->front == Q->rear);
}

// 处理队列满(数据搬移)
int queueFull(Queue *Q) {
    if (Q->front > 0) {
        int step = Q->front;
        for (int i = Q->front; i < Q->rear; ++i) {
            Q->data[i - step] = Q->data[i];
        }
        Q->front = 0;
        Q->rear -= step;
        return 1;
    } else {
        printf("队列已满,无法入队!\n");
        return 0;
    }
}

// 入队操作
int enqueue(Queue *Q, ElemType e) {
    if (Q->rear >= MAXSIZE) {
        if (!queueFull(Q)) {
            return 0;
        }
    }
    Q->data[Q->rear++] = e;
    return 1;
}

// 出队操作
ElemType dequeue(Queue *Q) {
    if (isEmpty(Q)) {
        printf("队列为空,无法出队!\n");
        return 0;
    }
    return Q->data[Q->front++];
}

// 获取队头元素(不删除)
int getHead(Queue *Q, ElemType *e) {
    if (isEmpty(Q)) {
        printf("队列为空,无队头元素!\n");
        return 0;
    }
    *e = Q->data[Q->front];
    return 1;
}

// 销毁队列(释放动态内存)
void destroyQueue(Queue *Q) {
    free(Q->data); // 先释放数据数组
    free(Q);       // 再释放队列结构体
}

// 主函数:测试队列操作
int main() {
    Queue *q = initQueue(); // 创建并初始化队列

    // 入队测试
    enqueue(q, 10);
    enqueue(q, 20);
    enqueue(q, 30);
    enqueue(q, 40);
    enqueue(q, 50);

    // 出队测试
    printf("出队元素:%d\n", dequeue(q));
    printf("出队元素:%d\n", dequeue(q));

    // 获取队头测试
    ElemType e;
    if (getHead(q, &e)) {
        printf("当前队头元素:%d\n", e);
    }

    // 继续入队,触发数据搬移
    enqueue(q, 60);
    enqueue(q, 70);

    // 清空队列
    while (!isEmpty(q)) {
        printf("出队元素:%d\n", dequeue(q));
    }

    destroyQueue(q); // 销毁队列,释放内存
    return 0;
}

三、代码总结

  1. 核心概念

    • 顺序队列是用数组实现的 "先进先出(FIFO)" 数据结构。
    • front 指向队头,rear 指向队尾下一个位置,front == rear 表示队空。
    • 静态数组队列存在 "假溢出" 问题,通过数据搬移queueFull函数)解决。
    • 动态版队列用malloc分配内存,更灵活,需手动释放内存避免泄漏。
  2. 核心操作

    • 初始化 :将frontrear置为 0(动态版还需分配内存)。
    • 入队 :向rear位置存元素,rear自增;满时尝试数据搬移。
    • 出队 :取front位置元素,front自增;空时提示错误。
    • 查队头 :读取front位置元素,不修改指针。
    • 销毁:释放动态分配的数组和结构体内存。
  3. 优缺点

    • ✅ 优点:实现简单,访问元素速度快(数组随机访问)。
    • ❌ 缺点:静态版容量固定,假溢出需额外处理;动态版需手动管理内存。
    • 💡 优化方向:可改用循环队列(取模运算)避免假溢出,无需数据搬移。

四、运行结果示例

相关推荐
W23035765731 小时前
经典算法:最长上升子序列(LIS)深度解析 C++ 实现
开发语言·c++·算法
.Ashy.1 小时前
2026.4.11 蓝桥杯软件类C/C++ G组山东省赛 小记
c语言·c++·蓝桥杯
2401_892070981 小时前
链栈(链式栈) 超详细实现(C 语言 + 逐行精讲)
c语言·数据结构·链栈
minji...2 小时前
Linux 线程同步与互斥(三) 生产者消费者模型,基于阻塞队列的生产者消费者模型的代码实现
linux·运维·服务器·开发语言·网络·c++·算法
语戚3 小时前
力扣 968. 监控二叉树 —— 贪心 & 树形 DP 双解法递归 + 非递归全解(Java 实现)
java·算法·leetcode·贪心算法·动态规划·力扣·
skywalker_113 小时前
力扣hot100-7(接雨水),8(无重复字符的最长子串)
算法·leetcode·职场和发展
bIo7lyA8v4 小时前
算法稳定性分析中的输入扰动建模的技术9
算法
CoderCodingNo4 小时前
【GESP】C++三级真题 luogu-B4499, [GESP202603 三级] 二进制回文串
数据结构·c++·算法
sinat_286945194 小时前
AI Coding 时代的 TDD:从理念到工程落地
人工智能·深度学习·算法·tdd