当前位置: 首页 > news >正文

《数据结构笔记六》队列 ⭐⭐⭐

一、队列的基本概念与特性

队列(Queue) 是一种 先进先出(FIFO, First In First Out) 的线性数据结构,核心操作包括:

  • enqueue:元素入队(添加到队尾)

  • dequeue:元素出队(移除队首元素)

  • front:查看队首元素(不移除)

  • isEmpty:判断队列是否为空

  • isFull:判断队列是否已满(仅限固定容量队列)


二、C语言实现队列(基于循环数组)

1. 队列的结构定义
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>#define MAX_SIZE 5  // 队列的最大容量typedef struct {int front;      // 队首指针(指向第一个元素)int rear;       // 队尾指针(指向最后一个元素的下一个位置)int capacity;   // 队列容量int* array;     // 存储元素的数组
} Queue;
2. 核心操作函数
// 初始化队列
Queue* createQueue(int capacity) {Queue* queue = (Queue*)malloc(sizeof(Queue));queue->capacity = capacity;queue->front = 0;queue->rear = 0;queue->array = (int*)malloc(capacity * sizeof(int));return queue;
}
// 判断队列是否为空
bool isEmpty(Queue* queue) {return queue->front == queue->rear;
}
// 判断队列是否已满
bool isFull(Queue* queue) {return (queue->rear + 1) % queue->capacity == queue->front;
}// 入队操作
void enqueue(Queue* queue, int item) {if (isFull(queue)) {printf("Queue is full! Cannot enqueue %d\n", item);return;}queue->array[queue->rear] = item;queue->rear = (queue->rear + 1) % queue->capacity;  // 循环移动指针
}// 出队操作
int dequeue(Queue* queue) {if (isEmpty(queue)) {printf("Queue is empty!\n");return -1;  // 错误码}int item = queue->array[queue->front];queue->front = (queue->front + 1) % queue->capacity;  // 循环移动指针return item;
}
// 查看队首元素
int front(Queue* queue) {if (isEmpty(queue)) {printf("Queue is empty!\n");return -1;}return queue->array[queue->front];
}
// 释放队列内存
void freeQueue(Queue* queue) {free(queue->array);free(queue);
}
3. 测试用例
int main() {Queue* queue = createQueue(MAX_SIZE);enqueue(queue, 10);enqueue(queue, 20);enqueue(queue, 30);enqueue(queue, 40);  // 队列满(MAX_SIZE=5时实际可用容量为4,因循环队列需浪费一个位置)printf("Front element: %d\n", front(queue));  // 应输出10printf("Dequeued: %d\n", dequeue(queue));     // 10出队printf("Dequeued: %d\n", dequeue(queue));     // 20出队enqueue(queue, 50);  // 入队50enqueue(queue, 60);  // 入队60printf("Queue is full? %s\n", isFull(queue) ? "Yes" : "No");  // 应输出YesfreeQueue(queue);return 0;
}

三、深度分析

1. 循环数组设计的必要性
  • 假溢出问题
    普通数组实现队列时,rear指针到达数组末尾后即使前面有空位也无法继续入队(假溢出)。
    循环数组通过取模运算((rear + 1) % capacity)实现指针循环,复用空闲空间。

  • 队列空/满判断

    • 空队列front == rear

    • 满队列(rear + 1) % capacity == front

    • 牺牲一个存储单元:为了区分空和满状态,实际可用容量为 capacity - 1

2. 核心操作的时间复杂度
操作时间复杂度说明
enqueueO(1)直接操作队尾指针
dequeueO(1)直接操作队首指针
frontO(1)直接访问队首元素
isEmptyO(1)检查 front == rear
3. 数组实现 vs 链表实现
特性数组实现链表实现
内存占用固定容量,可能浪费空间动态分配,无容量限制
扩容成本需重新分配内存并复制数据(O(n))动态添加节点(O(1))
访问速度缓存友好,连续内存访问指针跳转,缓存不友好
实现复杂度需处理循环指针逻辑需维护头尾节点指针
4. 应用场景
  • 任务调度:操作系统中的进程就绪队列。

  • 数据缓冲:网络数据包的接收缓冲区。

  • 广度优先搜索(BFS):按层级遍历树或图。

  • 打印机任务队列:按顺序处理打印请求。


四、链表实现队列

typedef struct Node {int data;struct Node* next;
} Node;typedef struct {Node* front;  // 队首指针Node* rear;   // 队尾指针
} LinkedQueue;// 初始化链表队列
LinkedQueue* createLinkedQueue() {LinkedQueue* queue = (LinkedQueue*)malloc(sizeof(LinkedQueue));queue->front = queue->rear = NULL;return queue;
}// 入队(链表尾插法)
void linkedEnqueue(LinkedQueue* queue, int data) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = data;newNode->next = NULL;if (queue->rear == NULL) {  // 空队列queue->front = queue->rear = newNode;} else {queue->rear->next = newNode;queue->rear = newNode;}
}// 出队
int linkedDequeue(LinkedQueue* queue) {if (queue->front == NULL) return -1;Node* temp = queue->front;int data = temp->data;queue->front = queue->front->next;if (queue->front == NULL) {  // 队列空后重置rearqueue->rear = NULL;}free(temp);return data;
}

五、关键设计细节

  1. 循环指针的数学运算

    • 入队时更新 rearrear = (rear + 1) % capacity

    • 出队时更新 frontfront = (front + 1) % capacity

  2. 动态扩容策略(可选)

    • 当队列满时,可分配更大的数组并迁移数据(例如容量翻倍)。

  3. 错误处理

    • 入队时检测队列满,出队时检测队列空。

  4. 内存管理

    • 链表实现需逐个释放节点内存。


六、总结

  • 队列的核心思想:通过限制操作位置(队尾入队、队首出队),强制实现FIFO逻辑。

  • 实现选择

    • 需要快速访问和固定容量时选择数组实现。

    • 需要动态扩容时选择链表实现。

  • 应用本质:队列适用于需要“顺序处理”的场景,如任务调度、数据缓冲等。

通过代码实现和理论分析,可以更深入地理解队列在算法和系统开发中的应用价值。

http://www.xdnf.cn/news/698275.html

相关文章:

  • Dolphin文档解析从理论到实践——保姆级教程
  • 【MySQL】第12节|MySQL 8.0 主从复制原理分析与实战(二)
  • VisionPro —— 上料检测模拟
  • AVL树
  • Kotlin扩展函数与属性实战指南:从入门到企业级应用
  • 【c++】【数据结构】红黑树
  • 【位运算】常见位运算总结
  • 云原生架构,各行业数字化转型法宝
  • 回归任务损失函数对比曲线
  • vue3+Pinia+element-plus 后台管理系统项目实战记录
  • 2..3...4.... Wonderful! Wonderful!_cf1930E分析与解答
  • SpringBoot 验证码练习
  • GRASS GIS 生成斜坡单元
  • Opengl纹理采样
  • 【C语言练习】069. 使用goto语句实现复杂的跳转
  • XCTF-web-mfw
  • socket编程预备
  • 基于DFT码本的波束方向图生成MATLAB实现
  • 【AUTOSAR OS 】保护功能解析:从原理到应用与源代码解析(上篇)
  • MySQL复杂查询与Union操作
  • SQLite数据库取证分析
  • 用 Python 构建跨平台前端界面:深入解读 Flet 库
  • windows本地虚拟机上运行docker-compose案例
  • QT开发技术 【元对象系统反射机制 】三
  • 中阳视角:如何通过波动率识别市场节奏变化
  • Android Zygote通信协议深度解析
  • c++lambda表达式
  • Linux文件传输——curl命令详介
  • SAR ADC 比较器的offset 校正
  • 西门子SCL语言编写两台电机正反转控制程序,并涵盖从选型、安装到调试全过程的详细步骤指南(上)