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防止重复点击
这样效果仅生效在按钮上...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...