C语言实现队列
队列
- 前言
- 一、队列的结构
- 1.实现思路
- 2.代码结构
- 二、队列的实现
- 1.初始化和销毁
- 2.判空和获取队列大小
- 3.入队列和出队列
- 4.获取队头和队尾元素
- 5.测试
- 总结
- 每文推荐
前言
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
一、队列的结构
1.实现思路
队列的结构特点最核心的就是先进先出四个字,和栈类似,我们在实现队列这个数据结构时首先需要考虑的就是使用顺序表来实现还是使用链表来实现,而考虑的主要因素就是该结构是否可以满足或者说是否可以更方便地实现队列的核心特点先进先出。如果没有看过顺序表和链表的实现的,可以先看一下我之前的文章。
顺序表的实现
单向链表的实现
双向链表的实现
这里我们简单地分析一下,如果使用顺序表,那么实现队列就会变得比较麻烦,因为顺序表的尾插尾删效率确实很高,但它的头插头删效率就很一般了,因为顺序表的头插头删都需要我们对顺序表里面的元素进行前移或后移,这是一个时间复杂度为O(N) 的操作,效率是非常一般的,而我们如果使用顺序表来实现队列的话,我们的入队列即是尾插还是很不错,但是出队列即是头删的效率就非常一般了,所以我们在实现队列的时候不推荐使用顺序表。
而如果使用链表,链表的优势就体现出来了,因为链表对于头插头删或者尾插尾删来说效率是非常高的,只需要申请新结点后进行链接操作即可,所以我们推荐使用链表来实现队列。我们在队列的结构中需要用两个变量来分别记录队头(头结点)和队尾(尾结点)的位置以及一个变量来记录当前队列的大小,当然,如果使用双向循环链表的话甚至不用单独记录队头和队尾,不过相应地如果使用双向链表的话进行链接操作时会变得更复杂。而队列的先进先出也就是链表的尾插头删,效率非常高。
2.代码结构
// 链式结构:表示队列
typedef int QDataType;typedef struct QListNode
{struct QListNode* _next;QDataType _data;
}QNode;// 队列的结构
typedef struct Queue
{QNode* _front;QNode* _rear;int size;
}Queue;
在本篇文章中,我们就使用单链表来实现一个队列。在C语言中,我们先用一个结构体定义一个链表的结点,在这里即是这个struct QListNode的结构体并将其typedef重命名为QNode,之后我们再用一个结构体来定义一个队列,在这里即是这个struct Queue的结构体并将其typedef重命名为Queue,便于后面书写的简便性。在这个队列的结构中,我们需要定义两个QNode类型的指针来分别记录队列的队头位置和队尾位置,然后再定义一个整形类型的变量来记录当前队列的大小。同时为了方便我们以后更改队列的存储数据类型,我们可以在这里将类型进行typedef,即typedef int QDataType,将int重命名为QDataType,这样以后我们只用在这里更改类型即可更改队列的存储的数据类型。
二、队列的实现
1.初始化和销毁
// 初始化队列
void QueueInit(Queue* q)
{assert(q);q->_front = NULL;q->_rear = NULL;q->size = 0;
}
初始化队列的函数,我们传入一个Queue类型的指针,然后将其内部完成初始化操作。即将队头和队尾位置赋值为空,然后将队列大小赋值为0。
// 销毁队列
void QueueDestroy(Queue* q)
{assert(q);QNode* cur = q->_front;while (cur){QNode* del = cur;cur = cur->_next;free(del);del = NULL;}q->_front = NULL;q->_rear = NULL;q->size = 0;
}
销毁队列的函数,类似地,我们传入一个Queue类型的指针,然后遍历链表,依次使用free函数释放每个结点,这里和单向链表的销毁一模一样,最后我们再将队列的队头和队尾位置赋值为空并将队列大小赋值为0完成队列的销毁操作。
2.判空和获取队列大小
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q)
{assert(q);return q->_front == NULL;
}
判断队列是否为空的函数,这个函数非常简单,一句return q->_front == NULL就可以搞定,如果当前队列的队头位置为空,那么该队列就为空队列,这句语句就为真,为真就返回非0结果,反之不为空这句语句即为假,为假就返回0。当然这里判空的语句不一定要用队头位置是否为空来判断,用队尾位置是否为空或者队列的大小是否为0来判断也都是没问题的。
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{assert(q);return q->size;
}
获取队列中有效元素个数的函数,这个函数非常简单,我们直接返回记录队列大小的size的值即可。
3.入队列和出队列
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{assert(q);QNode* pnew = (QNode*)malloc(sizeof(QNode));if (pnew == NULL){perror("malloc");exit(-1);}pnew->_data = data;pnew->_next = NULL;if (q->size == 0){q->_front = pnew;q->_rear = pnew;}else{q->_rear->_next = pnew;q->_rear = pnew;}q->size++;
}
进行入队列操作的函数,这个函数就和链表的尾插函数完全类似。首先我们需要进行申请新结点的操作,我们利用malloc函数在堆上申请一个新结点,然后将入队列的值data赋值给新结点中的_data并将_next指针初始化为空完成申请新结点的操作。之后我们就进行链接操作,这里就和单链表的尾插完全类似。我们首先进行分类讨论看当前链表是否为空,如果当前链表为空的话我们就直接让队头和队尾位置指向新开辟的结点pnew;如果不为空的话,我们就让我们的队尾结点_rear的_next指针指向新结点并将队尾结点_rear更新为新结点。最后我们将队列的大小size加1即可完成入队列的操作。
// 队头出队列
void QueuePop(Queue* q)
{assert(q);if (QueueEmpty(q)){printf("当前队列为空\n");return;}if (q->_front == q->_rear){free(q->_front);q->_front = NULL;q->_rear = NULL;}else{QNode* del = q->_front;q->_front = del->_next;free(del);del = NULL;}q->size--;
}
进行出队列操作的函数,同理,这个函数和链表的头删函数类似,我们先进行判空操作,保证出队列时队列不能为空,如果不为空我们才进行出队列操作。然后出队列操作我们也进行一个分类讨论,讨论一下当前队列的大小是否为1,即队头q->_front是否等于队尾q->_rear,因为这涉及到我们是否需要更改队尾的位置。如果大小为1,我们就用free函数释放这一个结点,然后将队头和队尾都赋值为空;如果大小不为1,我们就先用一个变量del记录当前的队头位置,然后将队头位置_front指向队头的_next位置并释放del记录的之前的队头位置。最后我们将队列的大小size减1即可完成出队列操作。
4.获取队头和队尾元素
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{assert(q);if (q->size == 0){printf("无元素\n");return 0;}return q->_front->_data;
}
获取队列头部元素的函数,我们先进行一个判空操作,如果队列为空则提前返回,如果不为空就返回队头位置_front的数据。
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{assert(q);if (q->size == 0){printf("无元素\n");return 0;}return q->_rear->_data;
}
获取队列队尾元素的函数,同理,我们也先进行一个判空操作,如果队列为空则提前返回,如果不为空就返回队尾位置_rear的数据。
5.测试
进行测试的main函数,用来测试我们写的队列的逻辑是否存在问题。
int main()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);printf("%d\n", QueueBack(&q));printf("%d ", QueueFront(&q));QueuePop(&q);printf("%d ", QueueFront(&q));QueuePop(&q);printf("%d ", QueueFront(&q));QueuePop(&q);printf("%d ", QueueFront(&q));QueuePop(&q);printf("\n");QueuePop(&q);printf("\n");printf("%d ", QueueSize(&q));printf("\n");printf("%d\n", QueueFront(&q));printf("%d\n", QueueBack(&q));printf("%d\n", QueueEmpty(&q));QueueDestroy(&q);return 0;
}
总结
本章到这里数据结构队列的实现就已经全部完成了,队列的实现难度其实不是特别大,特别是如果亲自实现过前面的顺序表和链表的话,难度应该会更小。虽然队列看起来简单,但我们不能忽视它的重要性,它的作用包括但不限于任务调度,事件处理,缓存机制,并发控制,算法实现等方面。所以虽然结构基础,但它的意义却是非常之大,值得我们亲自去实现它。
如需源码,可在我的gitee上找到,下面是链接。
队列源码
如对您有所帮助,可以来个三连,感谢大家的支持。
每文推荐
张靓颖–念念不忘
A-Lin–天若有情
梁静茹–慢冷
学技术学累了时可以听歌放松一下。
相关文章:
C语言实现队列
队列 前言一、队列的结构1.实现思路2.代码结构 二、队列的实现1.初始化和销毁2.判空和获取队列大小3.入队列和出队列4.获取队头和队尾元素5.测试 总结每文推荐 前言 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操…...
Python使用scrapy创建项目爬虫步骤
一、安装导入 使用包管理器下载 pip install scrapy 二、创建Scrapy项目 首先需要进入你创建项目的目录下,打开cmd窗口或powershell窗口: scrapy startproject 项目名称(英文) 三、了解项目结构 scrapy.cfg # 项目的配置文件…...
长沙某公司.Net高级开发面试题
1.dot net core跟dot net比较有哪些更好的地方? 第一是跨平台,它可以运行在三大操作系统上面,windows, Linux和MAC。 第二是对架构本身安装没有依赖,因为所有的依赖都跟程序本身在一起。 第三是dot net core处理请求…...
物联网系统中声音拾取音频方案_咪头
01 物联网系统中为什么要使用咪头 物联网系统中使用咪头(麦克风或传声器)的原因主要可以归结为以下几个方面: 声音信号的拾取与转换 基本功能:咪头是一种将声音转换为电信号的装置。在物联网系统中,咪头负责捕捉周围…...
【题解】Codeforces Round 975 (Div. 2) A~E
A. Max Plus Size 分别假设答案为取第偶数位的最大值和取第奇数位的最大值两种情况, 取更优解. 取偶数位的最大值时, 把所有其他都偶数位都取上. 奇数同理. code: int solve(int _) {int n;cin >> n;vector<int>a(n 1);int Maxj 0, Maxo 0;for (int i 1; i …...
如何搞定视频裁剪?新手小白零基础剪辑,分享5个实用工具!
现在是一个短视频盛行的时代,几乎每个人都掌握了视频剪辑技能。 不管是因为工作也好,生活也罢,只要有视频,那么就一定会用到视频剪辑软件。视频裁剪已经难不倒普通人了,借助专业的视频裁剪工具,任何人都可…...
HttpClientHandler 详解及使用
在现代网络编程中,HttpClientHandler 是一个至关重要的组件,它提供了对 HTTP 请求的底层配置和控制。本文将详细介绍 HttpClientHandler 的核心概念、配置选项以及如何在实际应用中使用它。 1. 什么是 HttpClientHandler? HttpClientHandle…...
基于两分支卷积和 Transformer 的轻量级多尺度特征融合超分辨率网络 !
当前的单图像超分辨率(SISR)算法有两种主要的深度学习模型,一种是基于卷积神经网络(CNN)的模型,另一种是基于Transformer的模型。前者利用不同卷积核大小的卷积层堆叠来设计模型,使得模型能够更…...
Font Awesome 手势图标
Font Awesome 手势图标 Font Awesome 是一个广泛使用的图标库,它为网页设计师和开发者提供了一系列高质量的图标。这些图标涵盖了从基本的网页元素到复杂的符号和手势,可以轻松地集成到各种网页和应用中。在本文中,我们将重点介绍 Font Awesome 中的手势图标,探讨它们的应…...
基于Hive和Hadoop的哔哩哔哩网站分析系统
本项目是一个基于大数据技术的哔哩哔哩平台分析系统,旨在为用户提供全面的哔哩哔哩视频数据和深入的用户行为分析。系统采用 Hadoop 平台进行大规模数据存储和处理,利用 MapReduce 进行数据分析和处理,通过 Sqoop 实现数据的导入导出…...
Augular 学习步骤建议
Angular 是一个由 Google 维护的开源 Web 应用框架,用于开发单页面客户端应用程序。以下是学习 Angular 的建议步骤: 1. 了解基础: 熟悉 HTML、CSS 和 JavaScript 的基础知识。 了解 TypeScript,因为 Angular 应用程序主要使用…...
突破自闭症治疗进展报道:改变孩子和家庭的未来
在这个充满挑战与希望的时代,自闭症这一复杂的神经发育障碍,长久以来一直是无数家庭心中的痛。然而,在星贝育园这片充满爱与科学的土地上,一场关于自闭症治疗的深刻变革正在悄然发生,它不仅为孩子们点亮了未来的希望之…...
我想注册一批账号做矩阵,需要每次注册都切换一个ip吗
在注册一批账号以建立矩阵时,切换IP地址是一个重要的考虑因素,尤其是为了避免被平台识别为同一用户或多重账户,从而减少账号被封的风险。以下是一些建议,帮助你有效管理IP地址和账号注册过程: 1. 切换IP地址的必要性 …...
linux系统的常用命令
微服务Linux解析部署使用全流程 Linux安装vim超详细教程 Linux安装JDK及配置环境变量超详细教程 Linux安装tomcat及配置环境变量超详细教程 目录 1、ls:列出目录内容。 2、cd:改变当前目录。 3、pwd:打印当前工作目录的路径 4、mkdir…...
无锡卓瓷X哲讯智能科技,SAP项目正式启动!
在数字化浪潮的推动下,高精密陶瓷行业的领军企业—无锡卓瓷科技有限公司,携手哲讯智能科技有限公司近期启动SAP&BI项目,以打造行业领先的数字化管理平台。这一战略举措标志着无锡卓瓷在数字化转型的道路上迈出了坚实的一步。 无锡卓瓷—…...
Python从入门到精通-基础篇
1.Python的起源 1989年,为了打发圣诞节假期,Gudio van Rossum(吉多范罗苏姆(龟叔))决心开发一个新的解释程序(Python雏形) 1991年,第一个Python解释器诞生 Python这个…...
系统架构设计师-知识产权与标准化
目录 一、保护范围与对象 二、保护期限 三、知识产权人确定 四、侵权判断 五、标准化 一、保护范围与对象 知识产权是权利人依法就下列课题享有的专有权利: (一)作品(著作) (二)发明、实用…...
Python安装流程(Windows + MAC)
目录 Windows 版 1.下载Python 2.开始安装 3.配置环境变量 4.测试python是否成功安装 MAC版 1.下载Python 2.开始安装 Windows 版 1.下载Python 进入Python官网下载:(Python更新频繁,下载最新版即可,安装流程一致&#x…...
在 Qt 项目中使用 spdlog 的全攻略
目录 1. 准备工作:安装 spdlog 方法一:使用 CMake 的 FetchContent(推荐) 方法二:手动下载并添加到项目中 2. 在 Qt 项目中集成 spdlog a. 初始化 spdlog b. 在 Qt 的各个部分使用 spdlog 3. 基本使用示例 4. …...
vue的el-button防止重复点击
这样效果仅生效在按钮上...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
