【数据结构实战】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. 优缺点

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

四、运行结果示例

相关推荐
SuperByteMaster6 小时前
keil 工程 .gitignore配置文件
c语言
超级码力6666 小时前
【Latex文件架构】Latex文件架构模板
算法·数学建模·信息可视化
穿条秋裤到处跑7 小时前
每日一道leetcode(2026.04.29):二维网格图中探测环
算法·leetcode·职场和发展
Merlos_wind7 小时前
HashMap详解
算法·哈希算法·散列表
汉克老师8 小时前
GESP2025年3月认证C++五级( 第三部分编程题(1、平均分配))
c++·算法·贪心算法·排序·gesp5级·gesp五级
Yzzz-F10 小时前
Problem - 2205D - Codeforces
算法
老花眼猫10 小时前
编制椭圆旋转绘图函数
c语言·经验分享·青少年编程·课程设计
智者知已应修善业11 小时前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
Halo_tjn11 小时前
Java Set集合相关知识点
java·开发语言·算法
生成论实验室11 小时前
《事件关系阴阳博弈动力学:识势应势之道》第四篇:降U动力学——认知确定度的自驱演化
人工智能·科技·神经网络·算法·架构