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

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个实用工具!

现在是一个短视频盛行的时代&#xff0c;几乎每个人都掌握了视频剪辑技能。 不管是因为工作也好&#xff0c;生活也罢&#xff0c;只要有视频&#xff0c;那么就一定会用到视频剪辑软件。视频裁剪已经难不倒普通人了&#xff0c;借助专业的视频裁剪工具&#xff0c;任何人都可…...

HttpClientHandler 详解及使用

在现代网络编程中&#xff0c;HttpClientHandler 是一个至关重要的组件&#xff0c;它提供了对 HTTP 请求的底层配置和控制。本文将详细介绍 HttpClientHandler 的核心概念、配置选项以及如何在实际应用中使用它。 1. 什么是 HttpClientHandler&#xff1f; HttpClientHandle…...

基于两分支卷积和 Transformer 的轻量级多尺度特征融合超分辨率网络 !

当前的单图像超分辨率&#xff08;SISR&#xff09;算法有两种主要的深度学习模型&#xff0c;一种是基于卷积神经网络&#xff08;CNN&#xff09;的模型&#xff0c;另一种是基于Transformer的模型。前者利用不同卷积核大小的卷积层堆叠来设计模型&#xff0c;使得模型能够更…...

Font Awesome 手势图标

Font Awesome 手势图标 Font Awesome 是一个广泛使用的图标库,它为网页设计师和开发者提供了一系列高质量的图标。这些图标涵盖了从基本的网页元素到复杂的符号和手势,可以轻松地集成到各种网页和应用中。在本文中,我们将重点介绍 Font Awesome 中的手势图标,探讨它们的应…...

基于Hive和Hadoop的哔哩哔哩网站分析系统

本项目是一个基于大数据技术的哔哩哔哩平台分析系统&#xff0c;旨在为用户提供全面的哔哩哔哩视频数据和深入的用户行为分析。系统采用 Hadoop 平台进行大规模数据存储和处理&#xff0c;利用 MapReduce 进行数据分析和处理&#xff0c;通过 Sqoop 实现数据的导入导出&#xf…...

Augular 学习步骤建议

Angular 是一个由 Google 维护的开源 Web 应用框架&#xff0c;用于开发单页面客户端应用程序。以下是学习 Angular 的建议步骤&#xff1a; 1. 了解基础&#xff1a; 熟悉 HTML、CSS 和 JavaScript 的基础知识。 了解 TypeScript&#xff0c;因为 Angular 应用程序主要使用…...

突破自闭症治疗进展报道:改变孩子和家庭的未来

在这个充满挑战与希望的时代&#xff0c;自闭症这一复杂的神经发育障碍&#xff0c;长久以来一直是无数家庭心中的痛。然而&#xff0c;在星贝育园这片充满爱与科学的土地上&#xff0c;一场关于自闭症治疗的深刻变革正在悄然发生&#xff0c;它不仅为孩子们点亮了未来的希望之…...

我想注册一批账号做矩阵,需要每次注册都切换一个ip吗

在注册一批账号以建立矩阵时&#xff0c;切换IP地址是一个重要的考虑因素&#xff0c;尤其是为了避免被平台识别为同一用户或多重账户&#xff0c;从而减少账号被封的风险。以下是一些建议&#xff0c;帮助你有效管理IP地址和账号注册过程&#xff1a; 1. 切换IP地址的必要性 …...

linux系统的常用命令

微服务Linux解析部署使用全流程 Linux安装vim超详细教程 Linux安装JDK及配置环境变量超详细教程 Linux安装tomcat及配置环境变量超详细教程 目录 1、ls&#xff1a;列出目录内容。 2、cd&#xff1a;改变当前目录。 3、pwd&#xff1a;打印当前工作目录的路径 4、mkdir…...

无锡卓瓷X哲讯智能科技,SAP项目正式启动!

在数字化浪潮的推动下&#xff0c;高精密陶瓷行业的领军企业—无锡卓瓷科技有限公司&#xff0c;携手哲讯智能科技有限公司近期启动SAP&BI项目&#xff0c;以打造行业领先的数字化管理平台。这一战略举措标志着无锡卓瓷在数字化转型的道路上迈出了坚实的一步。 无锡卓瓷—…...

Python从入门到精通-基础篇

1.Python的起源 1989年&#xff0c;为了打发圣诞节假期&#xff0c;Gudio van Rossum&#xff08;吉多范罗苏姆&#xff08;龟叔&#xff09;&#xff09;决心开发一个新的解释程序&#xff08;Python雏形&#xff09; 1991年&#xff0c;第一个Python解释器诞生 Python这个…...

系统架构设计师-知识产权与标准化

目录 一、保护范围与对象 二、保护期限 三、知识产权人确定 四、侵权判断 五、标准化 一、保护范围与对象 知识产权是权利人依法就下列课题享有的专有权利&#xff1a; &#xff08;一&#xff09;作品&#xff08;著作&#xff09; &#xff08;二&#xff09;发明、实用…...

Python安装流程(Windows + MAC)

目录 Windows 版 1.下载Python 2.开始安装 3.配置环境变量 4.测试python是否成功安装 MAC版 1.下载Python 2.开始安装 Windows 版 1.下载Python 进入Python官网下载&#xff1a;&#xff08;Python更新频繁&#xff0c;下载最新版即可&#xff0c;安装流程一致&#x…...

在 Qt 项目中使用 spdlog 的全攻略

目录 1. 准备工作&#xff1a;安装 spdlog 方法一&#xff1a;使用 CMake 的 FetchContent&#xff08;推荐&#xff09; 方法二&#xff1a;手动下载并添加到项目中 2. 在 Qt 项目中集成 spdlog a. 初始化 spdlog b. 在 Qt 的各个部分使用 spdlog 3. 基本使用示例 4. …...

vue的el-button防止重复点击

这样效果仅生效在按钮上...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

Python 高效图像帧提取与视频编码:实战指南

Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...