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

数据结构 -- 队列

队列的核心定义

队列是受限线性表,仅允许在一端(队尾)插入元素、另一端(队头)删除元素,遵循 “先进先出(FIFO,First In First Out)” 原则。

队列的结构与操作端

  • 队尾(Rear):允许执行插入操作(入队,Enqueue )的一端。
  • 队头(Front):允许执行删除操作(出队,Dequeue )的一端。

队列的实现与分类

  • 顺序队列:基于数组实现,需处理 “假溢出” 问题(队尾满但队头有空闲 )。
  • 循环队列:对顺序队列的优化,将数组逻辑处理为环形,通过队头、队尾指针模运算复用空间,解决假溢出。

队列的核心操作

  • 入队(Enqueue):在队尾添加元素,若队列未满则执行,队尾指针后移。
  • 出队(Dequeue):移除并返回队头元素,若队列非空则执行,队头指针后移。

队列的应用

队列的 “先进先出” 特性,核心解决 “速度不匹配” 场景:如网络通信中,收发数据速率不同(发送快、接收慢 ),用队列暂存数据做缓冲;或操作系统中,多个进程请求同一资源(如打印机 ),队列保证请求按顺序处理。简单说,队列就是用 “先进先出” 规则,解决 **“速度不匹配、需有序处理”** 问题的线性表,分顺序队列、循环队列

队列的操作函数

#include "seqque.h"   // 包含顺序队列的头文件,定义了SeqQue结构体和DATATYPE类型
#include <stdio.h>    // 标准输入输出库
#include <stdlib.h>   // 标准库,包含malloc、free等内存管理函数
#include <string.h>   // 字符串处理库,包含memcpy等内存拷贝函数/*** 创建一个顺序队列(循环队列)* @param len 队列的最大容量(可存储的元素个数)* @return 成功返回创建的队列指针,失败返回NULL*/
SeqQue* CreateSeqQue(int len)
{// 为队列控制结构体分配内存SeqQue* sq = malloc(sizeof(SeqQue));if (NULL == sq)  // 内存分配失败检查{perror("CreateSeqQue malloc");  // 打印错误信息return NULL;}// 为队列的数组缓冲区分配内存,可存储len个DATATYPE类型元素sq->array = malloc(sizeof(DATATYPE) * len);if (NULL == sq->array)  // 内存分配失败检查{perror("CreateSeqQue malloc2");  // 打印错误信息free(sq);  // 释放已分配的队列结构体内存,防止内存泄漏return NULL;}// 初始化队列指针:头指针和尾指针都从0开始sq->head = 0;sq->tail = 0;sq->tlen = len;  // 记录队列的总容量return sq;  // 返回创建成功的队列指针
}/*** 入队操作:向队列尾部添加元素* @param sq 队列指针* @param data 要入队的数据指针* @return 0表示成功,1表示失败(队列已满)*/
int EnterSeqQue(SeqQue* sq, DATATYPE* data)
{// 检查队列是否已满if (IsFullSeqQue(sq)){printf("queue is full\n");  // 提示队列已满return 1;  // 返回失败状态}// 将数据拷贝到队尾位置(tail指向的位置)memcpy(&sq->array[sq->tail], data, sizeof(DATATYPE));// 尾指针后移,使用取模运算实现循环(当到达数组末尾时回到开头)sq->tail = (sq->tail + 1) % sq->tlen;return 0;  // 返回成功状态
}/*** 出队操作:移除队列头部的元素* @param sq 队列指针* @return 0表示成功,1表示失败(队列已空)*/
int QuitSeqQue(SeqQue *sq)
{// 检查队列是否为空if (IsEmptySeqQue(sq)){printf("queue is empty\n");  // 提示队列已空return 1;  // 返回失败状态}// 头指针后移,使用取模运算实现循环(逻辑上移除队头元素)sq->head = (sq->head + 1) % sq->tlen;return 0;  // 返回成功状态
}/*** 获取队头元素(不移除元素)* @param sq 队列指针* @return 队头元素的指针,若队列为空则返回的指针无效*/
DATATYPE* GetHeadSeqQue(SeqQue* sq)
{// 直接返回头指针指向的元素地址return &sq->array[sq->head];
}/*** 判断队列是否为空* @param sq 队列指针* @return 1表示为空,0表示非空*/
int IsEmptySeqQue(SeqQue* sq)
{// 当头指针和尾指针指向同一位置时,队列为空return sq->head == sq->tail;
}/*** 判断队列是否已满* @param sq 队列指针* @return 1表示已满,0表示未满*/
int IsFullSeqQue(SeqQue* sq)
{// 尾指针的下一个位置等于头指针时,队列已满// 这种判断方式会浪费一个元素的空间,用于区分空队列和满队列return (sq->tail + 1) % sq->tlen == sq->head;
}/*** 销毁队列,释放占用的内存* @param sq 队列指针* @return 0表示成功*/
int DestroySeqQue(SeqQue* sq)
{free(sq->array);  // 释放数组缓冲区内存free(sq);         // 释放队列结构体内存return 0;
}

代码核心说明:

  1. 数据结构设计

    • 采用循环队列(环形缓冲区)的设计,通过数组实现
    • 使用head(头指针)和tail(尾指针)标识队列的边界
    • 牺牲一个元素的存储空间,用于区分队列空和满的状态
  2. 关键特性

    • 队列的实际可用容量为tlen - 1(因为要留一个位置区分空满)
    • 通过取模运算% sq->tlen实现指针的循环移动,避免数组越界
    • 所有操作的时间复杂度均为 O (1),效率很高
  3. 注意事项

    • 代码中SeqQue结构体和DATATYPE类型的定义在seqque.h头文件中
    • 入队和出队操作只移动指针,不实际删除数据(覆盖式更新)
    • 销毁队列时需要先释放数组内存,再释放结构体内存,避免内存泄漏
http://www.xdnf.cn/news/18410.html

相关文章:

  • Redis内存碎片深度解析:成因、检测与治理实战指南
  • Day16 二叉树part4
  • JDK21之虚拟线程的深入理解
  • Halcon那些事:什么是动态阈值,如何用dyn_threshold分割图片
  • 腾讯云COS SDK签名有效期设置为10分钟到期会自动刷新
  • Java后端学习路线
  • uniapp googlepay支付 内购项目
  • mysql编程(简单了解)
  • pthon实现bilibili缓存视频音频分离
  • 数据预处理学习笔记
  • 【C++】--函数参数传递:传值与传引用的深度解析
  • 防爆自动气象监测设备:高危环境的 “安全堡垒”
  • SpringBoot中的条件注解
  • 工作后的总结和反思1
  • 如何制定股指期货投机交易策略计划?
  • 数字社会学是干什么的?数字社会学理论与数字社会学家唐兴通讲数字社会学书籍有哪些?AI社会学人工智能社会学理论框架
  • 使用jwt+redis实现单点登录
  • LeetCode 回文链表
  • 力扣1005:k次取反后最大化的数组和
  • Elasticsearch官方文档学习-未完待续
  • 三层交换机
  • Bartender 5 多功能菜单栏管理(Mac电脑)
  • 【学习嵌入式day-29-网络】
  • 深入解析C++非类型模板参数
  • 网络打印机自动化部署脚本
  • 软考 系统架构设计师系列知识点之杂项集萃(130)
  • 记录前端菜鸟的日常——小程序内嵌H5页面自定义分享按钮
  • 深入解析HashMap的存储机制:扰动函数、哈希计算与索引定位
  • 信息收集4----(收集网站指纹信息)
  • 20250821 圆方树总结