数据结构-如何实现一个队列?逐步解析与代码示例(超详细)

文章目录
- 前言
- 1.队列的基本概念
- 2.链表与数组实现队列的区别
- 2.1数据存储结构
- 2.2性能
- 2.3内存使用
- 3.为什么选择链表实现队列?
- 4.结构定义
- 函数声明
- 5.核心操作
- 5.1初始化 (`QInit`)
- 5.2销毁 (`QDestroy`)
- 5.3入队 (`QPush`)
- 5.4出队 (`QPop`)
- 6.队列的查询操作
- 6.1队首元素 (`QueueFront`)
- 6.2队尾元素 (`QueueBack`)
- 7.辅助函数
- 7.1判断空 (`QueueEmpty`)
- 7.2队列大小 (`QueueSize`)
- 总结
前言
在计算机科学中,队列是一种非常基础且广泛使用的数据结构。它的工作原理类似于现实生活中的排队:先来的先服务(FIFO, First-In-First-Out)。在本文中,我们将深入探讨如何在C语言中使用链表实现一个队列,并解析相关的代码实现。
1.队列的基本概念
队列是一种遵循先进先出原则的线性数据结构。在队列中,添加操作(入队)发生在一端(队尾),而移除操作(出队)则发生在另一端(队首)。这种结构在多种场景中非常有用,如任务调度、数据缓冲等。

2.链表与数组实现队列的区别
当使用数组和链表实现队列时,主要区别在于数据存储结构、性能和内存使用:
2.1数据存储结构
数组:队列使用一个固定大小的数组。当数组满时,需要进行扩容,这可能涉及复制整个数组到新的内存位置。
链表:队列使用动态分配的节点,每个节点包含数据和指向下一个节点的指针。不需要事先分配固定大小的空间。
2.2性能
数组:入队和出队操作通常是O(1)复杂度,但当数组需要扩容时,复杂度会增加。
链表:由于不需要扩容,入队和出队操作始终保持O(1)复杂度。
2.3内存使用
数组:可能会有未使用的预留空间,特别是在队列大小波动较大时。
链表:每个元素单独分配,无需预留额外空间,但每个节点需要额外存储指针,略增加内存使用。
3.为什么选择链表实现队列?
在C语言中,链表是一种常用的数据结构,用于创建动态大小的序列。相比于数组实现,链表实现的队列具有动态分配内存的优点,不受固定大小的限制。
与基于数组的队列实现相比,链表实现的队列具有以下优势:
动态大小:不受固定长度的限制,可以根据需要动态扩展或收缩。
内存利用:每个元素仅在需要时分配内存,减少了空间浪费。
性能优化:避免了数组实现中可能发生的元素搬移操作。
接下来我们来用链表进行实现队列。
4.结构定义
该队列的实现基于两种结构:QueueNode 和 Queue。
typedef int QDataType; // 定义队列数据类型为int// 队列节点的结构体定义
typedef struct QueueNode
{QDataType val; // 节点存储的数据struct QueueNode* next; // 指向下一个节点的指针
} QNode;// 队列的结构体定义
typedef struct Queue
{QNode* phead; // 指向队列头部的指针QNode* ptail; // 指向队列尾部的指针int size; // 队列的大小
} Queue;
这里,QueueNode 表示队列中的每个节点,包含一个数据字段和一个指向下一个节点的指针。而Queue结构则持有指向队列头部和尾部的指针,并跟踪队列的当前大小。
函数声明
// 函数声明
void QInit(Queue* pq); // 初始化队列
void QDestroy(Queue* pq); // 销毁队列void QPush(Queue* pq, QDataType x); // 向队列中添加元素
void QPop(Queue* pq); // 从队列中移除元素QDataType QueueFront(Queue* pq); // 获取队列头部元素
QDataType QueueBack(Queue* pq); // 获取队列尾部元素bool QueueEmpty(Queue* pq); // 检查队列是否为空
int QueueSize(Queue* pq); // 获取队列的大小
5.核心操作
5.1初始化 (QInit)
初始化函数设置队列的头部和尾部指针为NULL,大小为0。这是创建队列的必要步骤。

// 初始化队列
void QInit(Queue* pq)
{assert(pq); // 断言队列指针非空pq->phead = pq->ptail = NULL; // 将头指针和尾指针都设为NULLpq->size = 0; // 将队列大小设置为0
}
5.2销毁 (QDestroy)
销毁函数释放队列中所有节点的内存,并重置队列的状态。这是队列不再使用时的清理步骤。

// 销毁队列
void QDestroy(Queue* pq)
{assert(pq); // 断言队列指针非空QNode* cur = pq->phead;while (cur){QNode* next = cur->next; // 保存下一个节点free(cur); // 释放当前节点cur = next; // 移动到下一个节点}pq->phead = NULL; // 将头指针设为NULLpq->ptail = NULL; // 将尾指针设为NULLpq->size = 0; // 将队列大小设置为0
}
5.3入队 (QPush)
在队列的尾部添加一个新元素。如果队列为空,则新元素同时成为头部和尾部元素。

// 向队列中添加元素
void QPush(Queue* pq, QDataType x)
{assert(pq); // 断言队列指针非空QNode* newNode = (QNode*)malloc(sizeof(QNode)); // 分配新节点内存if (newNode == NULL){perror("malloc fail"); // 内存分配失败处理exit(-1);}newNode->val = x; // 设置新节点的值newNode->next = NULL; // 新节点的下一个节点为NULLif (pq->ptail == NULL) // 如果队列为空{pq->phead = pq->ptail = newNode; // 队列头尾都指向新节点}else{pq->ptail->next = newNode; // 将新节点接到队列尾部pq->ptail = newNode; // 更新尾指针}pq->size++; // 队列大小增加
}
5.4出队 (QPop)
从队列的头部移除一个元素。如果队列为空,调整尾部指针。

// 从队列中移除元素
void QPop(Queue* pq)
{assert(pq); // 断言队列指针非空assert(pq->phead); // 断言队列不为空QNode* Del = pq->phead; // 保存要删除的节点pq->phead = pq->phead->next; // 更新头指针free(Del); // 释放节点内存if (pq->phead == NULL) // 如果队列变空{pq->ptail = NULL; // 更新尾指针}pq->size--; // 队列大小减少
}
6.队列的查询操作
6.1队首元素 (QueueFront)
返回队列头部节点的值,但不移除它。

// 获取队列头部元素的值
QDataType QueueFront(Queue* pq)
{assert(pq); // 断言队列指针非空assert(pq->phead); // 断言队列不为空return pq->phead->val; // 返回头部元素的值
}
6.2队尾元素 (QueueBack)
返回队列尾部节点的值。

// 获取队列尾部元素的值
QDataType QueueBack(Queue* pq)
{assert(pq); // 断言队列指针非空assert(pq->ptail); // 断言队列不为空return pq->ptail->val; // 返回尾部元素的值
}
7.辅助函数
7.1判断空 (QueueEmpty)
检查队列是否为空。

// 检查队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq); // 断言队列指针非空return pq->phead == NULL; // 如果头指针为NULL,则队列为空
}
7.2队列大小 (QueueSize)
返回队列中节点的数量。

// 获取队列的大小
int queueSize(Queue* pq)
{return pq->size; // 返回队列的大小
}
总结
理解队列的不同实现方式对于选择最适合特定应用场景的数据结构至关重要。链表实现的队列提供了灵活性和一致的性能,特别适用于大小不确定或需要频繁扩展的场景。而数组实现则在空间预分配和随机访问方面更有优势。深入了解这些差异,可以帮助程序员做出更明智的选择。我希望这篇文章能够帮助你更好地理解和实现队列。如果你有任何问题或想分享你的经验,请在评论区留言。
相关文章:
数据结构-如何实现一个队列?逐步解析与代码示例(超详细)
文章目录 前言1.队列的基本概念2.链表与数组实现队列的区别2.1数据存储结构2.2性能2.3内存使用 3.为什么选择链表实现队列?4.结构定义函数声明 5.核心操作5.1初始化 (QInit)5.2销毁 (QDestroy)5.3入队 (QPush)5.4出队 (QPop) 6.队列的查询操作6.1队首元素 (QueueFro…...
爬虫工作量由小到大的思维转变---<第二十三章 Scrapy开始很快,越来越慢(医病篇)>
诊断篇https://blog.csdn.net/m0_56758840/article/details/135170994?ops_request_misc%257B%2522request%255Fid%2522%253A%2522170333243316800180644102%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id1703332433168001806441…...
.Net7.0 或更高版本 System.Drawing.Common 上传图片跨平台方案
项目升级.Net7.0以后,System.Drawing.Common开关已经被删除,且System.Drawing.Common仅在 Windows 上支持 ,于是想办法将原来上传图片验证文件名和获取图片扩展名方法替换一下,便开始搜索相关解决方案。 .Net6.0文档:…...
【MySQL】InnoDB和MyISAM区别
文章目录 一、索引不同1 InnoDB聚簇索引,MyISAM非聚簇索引1 InnoDB聚簇索引2 MyISAM非聚簇索引 2 InnoDB必须要有主键,MyISAM允许没有主键3 InnoDB支持外键4 InnoDB不支持全文索引5 索引保存位置不同 二、对事物的支持三、存储结构不同四、存储空间不同五…...
3分钟了解安全数据交换系统有什么用!
企业为了保护核心数据安全,都会采取一些措施,比如做网络隔离划分,分成了不同的安全级别网络,或者安全域,接下来就是需要建设跨网络、跨安全域的安全数据交换系统,将安全保障与数据交换功能有机整合在一起&a…...
记录汇川:MODBUS TCP-梯形图
H5U的MODBUS通信不需要编写程序,通过组态MODBUS通信配置表,实现数据通信。 Modbus-TCP 主站即Modbus-TCP客户端,通过Modbus-TCP配置,可最多支持同时与31个 Modbus-TCP服务器(从站)进行通讯。 …...
electron + sqlite3 解决打包后无法写入数据库
前言 window环境。 electron28.0.0 sqlite35.1.6 使用 electron-builder 打包。 本文旨在解决打包后无法写入数据库的问题。 但如果你是打包后无法访问sqlite,且有报错弹窗,不妨也看看本文。 也许是同一种原因。 错误原因分析 打包后无法创建db文件&…...
【uniapp小程序-生成二维码+多个图片文字合并一张图】
<!-- 二维码 --><canvas id"qrcode" canvas-id"qrcode" width"120" ></canvas><!-- 生成带小程序码的分享图片 --><canvas canvas-id"shareCanvas" class"share-canvas"></canvas>#qrc…...
Text-to-SQL小白入门(十)RLHF在Text2SQL领域的探索实践
本文内容主要基于以下开源项目探索实践, Awesome-Text2SQL:GitHub - eosphoros-ai/Awesome-Text2SQL: Curated tutorials and resources for Large Language Models, Text2SQL, Text2DSL、Text2API、Text2Vis and more.DB-GPT-Hub:GitHub - eosphoros-ai…...
深度学习 | 基本循环神经网络
1、序列建模 1.1、序列数据 序列数据 —— 时间 不同时间上收集到的数据,描述现象随时间变化的情况。 序列数据 —— 文本 由一串有序的文本组成的序列,需要进行分词。 序列数据 —— 图像 有序图像组成的序列,后一帧图像可能会受前一帧的影响…...
VSCode 加Cortex-Debug嵌入式调试方法
简介 当使用ARM Cortex-M微控制器时,Cortex-Debug是一个Visual Studio Code的扩展,以简化调试过程。本文档介绍了如何编写启动配置(launch.json)。 settings.json配置 打开VSCode用户设置文件settings.json: 文件→偏好→设置选择用户设置: 在搜索栏中…...
etcd-workbench一款免费好用的ETCD客户端,支持SSHTunnel、版本对比等功能
介绍 今天推荐一款完全免费的ETCD客户端,可以私有化部署: etcd-workbench 开源地址:https://github.com/tzfun/etcd-workbench Gitee地址:https://gitee.com/tzfun/etcd-workbench 下载 本地运行 从 官方Release 下载最新版的 jar 包&am…...
华为ipv6配置之ospf案例
R1 ipv6 ospfv3 1 router-id 1.1.1.1 //必须要手动配置ospf id,它不会自动生成 interface GigabitEthernet0/0/0 ipv6 enable ipv6 address 2000::2/96 ospfv3 1 area 0.0.0.0 interface LoopBack0 ipv6 enable ipv6 address 2001::1/96 ospfv3 1 area 0.0.0.0 R2…...
Design patterns--装饰模式
设计模式之装饰模式 使用装饰模式来封装Nmea0183语句。 代码 #ifndef DATAPARSER_H #define DATAPARSER_H#include <string> #include <vector>class DataParser { public:DataParser();virtual std::string fieldAnalysis(std::vector<std::string> vecSt…...
卷积神经网络 反向传播
误差的计算 softmax 经过softmax处理后所有输出节点概率和为1 损失(激活函数) 多分类问题:输出只可能归于某一个类别,不可能同时归于多个类别。 误差的反向传播 求w的误差梯度 权值的更新...
java面试题20
Java中的类加载机制可继续通过自定义类加载器来实现热部署、插件化和动态加载等功能,使得应用程序能够在运行时加载未知的类和资源。 什么是Java中的多线程(Multithreading)?它有什么作用? 答案:多线程是一…...
【Java面试题】redis的过期策略有哪些
redis通过设置过期时间来控制键值对的存活时长,过期时间可以通过expire , pexpire expireat , pexpireat 等命令设置,String 类型数据可以通过setex命令设置过期时间。 以下介绍三种redis的过期策略: 1. 定时删除 在设置键值对的过期时…...
for参数 命令语句 变量
for 参数f skip命令语句 命令说明: 跳过文本内容(行):skip 例子: for /f "skip1" %%i in(2.txt) do echo %%i for 参数f eol命令语句 命令说明: 怱略指定字符的文本内容(文本首部…...
CentOS 8的新特性
CentOS 8在2019年发布,带来了比CentOS 7更多的新特性和改进。以下是一些主要的变化和优化: 软件包更新:CentOS 8提供了更新的软件包和程序,包括但不限于Python 3、MySQL 8、PHP 7.2、Ruby 2.5、PostgreSQL 10等。 应用流…...
vue2、vue3状态管理之vuex、pinia
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、状态管理之vuex1.1 State调用:1.2 Mutation在vuex中定义:在组件中使用: 1.3 Action在vuex中定义:将上面的减…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
