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

数据结构 -- 队列

队列的核心定义

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

队列的结构与操作端

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

队列的实现与分类

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

队列的核心操作

  • 入队(Enqueue):在队尾添加元素,若队列未满则执行,队尾指针后移。
  • 出队(Dequeue):移除并返回队头元素,若队列非空则执行,队头指针后移。
  • 循环队列判空:head == tail
  • 判满:(tail + 1) % len == head

队列的应用

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

队列的操作函数

#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.dtcms.com/a/344814.html

相关文章:

  • 【运维自动化-标准运维】变量的高级用法
  • 去中心化的私有货币与中心化的法定货币的对比分析
  • 数据结构与算法-算法-283移动零
  • 深度分析AI边缘盒子在电力行业的应用与发展
  • 【LeetCode】22. 括号生成
  • 欲打造未来感十足的规划馆,应优先引入哪些沉浸式多媒体技术?
  • Spring Start Here 读书笔记:第9章 Using the Spring web scopes
  • 人脸识别驱动的工厂人体属性检测与预警机制
  • C#开源库ACadSharp读取dwg图元的示例
  • 为何她在“传递情报”时会被干扰?—— 探究 TCP 协议在无线环境中的信号干扰问题
  • 算法题复盘+代码解读(2)—— 两数之和
  • 【功能测试面试题】
  • 【数据结构】B+ 树——高度近似于菌丝网络——详细解说与其 C 代码实现
  • CVPR焦点 | 神经网络新范式:轻量化与精度并行,重塑视觉任务性能天花板
  • 解释一下,Linux,shell,Vmware,Ubuntu,以及Linux命令和shell命令的区别
  • 1337俚语的由来
  • Seaborn数据可视化实战:Seaborn时间序列可视化入门
  • Linux学习-网络编程2
  • .java->.class->java 虚拟机中运行
  • 51.Seata-TCC模式
  • 前端函数防抖
  • Nginx + Keepalived 实现高可用负载均衡集群
  • 前端桌面端解决方案技术选型:全面指南
  • 深入理解强化学习的target network
  • 3.5MM防水耳机插座
  • 为什么访问HTTPS站点时,会发生SSL证书错误
  • JAVA基础代码示例
  • SpringBoot -- 集成Spring Security (二)
  • LightGBM时序预测详解:从原理到 PSO 参数优化
  • 如何理解面向过程和面向对象,举例说明一下?