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

手撕数据结构 —— 队列(C语言讲解)

目录

1.什么是队列

2.如何实现队列 

3.队列的实现

Queue.h中接口总览

具体实现

结构的定义

初始化

销毁

入队列

出队列

取队头元素

取队尾元素

判断是否为空

获取队列的大小 

4.完整代码附录

Queue.h

Queue.c


1.什么是队列

队列是一种特殊的线性表,只允许在一端进行数据的插入操作,在另一端进行数据的删除操作。队列中的数据元素必须满足先进先出的性质。

  • 插入数据的操作叫做入队列,插入数据的一端叫做队尾
  • 删除数据的操作叫做出队列,删除数据的一端叫做队头

队列逻辑结构如下图所示:

2.如何实现队列 

要想实现队列,必须满足队列的要求,也就是以下两点:

  • a、在一端插入数据,在另一端删除数据。
  • b、满足先进先出的性质。

所以,我们使用数组(顺序表)或者 链表实现,那么使用哪种结构来实现更好呢?

我们可以对比一下:

数组(顺序表)链表(单链表)
头插效率O(N)O(1)
头删效率O(N)O(1)
尾插效率O(1)O(N)
尾删效率O(1)O(N)

貌似使用数组和链表实现都是一样的,在一端进行插入or删除的效率是O(1),在另一端进行删除or插入的效率就是O(N) 。

但是我们可以优化一下链表,链表在尾部进行插入or删除的效率之所以是O(N),是因为需要遍历链表找尾结点,但是,如果我们能够直接找到尾结点,那么链表在尾部进行插入和删除的效率不就都是O(1)了吗?

所以,我们可以使用两个指针head和tail分别指向链表的头结点和尾结点。这样一来,进行尾插时,直接就能找到尾结点,所以尾插的效率也是O(1)。

所以我们实现的队列的最终形态如下:

3.队列的实现

队列的实现,我们主要实现Queue.h和Queue.c文件即可,Queue.h文件中存放声明,Queue.c文件中存放定义。

Queue.h中接口总览

具体实现

结构的定义

实现队列结构的时候,由于我们采用的是链表来实现队列,所以我们需要定义一个个的结点;前面我们分析可知,head指向头结点,tail指向尾结点,可以使得入队列和出队列的时间复杂度都为O(1),所以我们需要管理好head指针和tail指针,这里我们也采用结构体来管理。

初始化

初始化队列只需要初始化 struct Queue 结构体对象中的成员即可。

  • head和tail指针都初始化为空。
  • size初始化为0。

 

销毁

销毁队列的时候,首先需要将节点全部释放,然后将head和tail指针置空,并将size置为0。

入队列

入队列的时候要区分两种情况:

  • 入队列的结点是第一个结点,此时让head和tail同时指向该结点即可。
  • 入队列的结点不是第一个结点,此时让新结点连接到尾结点的后面即可。
  • 最后记得将size++。

出队列

出队列的时候要区分三种情况:

  • 队列不能为空。
  • 只有一个结点的情况。此时,释放结点之后,将head和tail指针置空。
  • 不止一个结点的情况。此时,记录head指向的结点,将head后移,然后释放记录的节点。

注意:最后记得将size--。

  

取队头元素

直接返回head指向的结点的数据即可。

取队尾元素

直接返回tail指向的结点的数据即可。

判断是否为空

当队列为空时,head和tail都指向空,所以直接判断head或者tail是否为空都可以。

获取队列的大小 

直接返回struct Queue结构体类型对象中的size即可。

4.完整代码附录

Queue.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int QDataType;
typedef struct QueueNode    // 定义结点 
{struct QueueNode* next; // 存储下一个结点的地址 QDataType data;         // 存储数据 
}QNode;typedef struct Queue        // 定义队列 
{QNode* head;            // 指向头结点 QNode* tail;            // 指向尾结点 int size;               // 记录队列的大小 
}Que;// 初始化 
void QueueInit(Que* pq);
// 销毁 
void QueueDestroy(Que* pq);
// 入队列 
void QueuePush(Que* pq, QDataType x);
// 出队列 
void QueuePop(Que* pq);
// 取队头元素 
QDataType QueueFront(Que* pq);
// 取队尾元素 
QDataType QueueBack(Que* pq);
// 判断是否为空 
bool QueueEmpty(Que* pq);
// 获取队列的大小 
int QueueSize(Que* pq);

Queue.c

// 初始化队列 
void QueueInit(Que* pq)
{assert(pq);pq->head = pq->tail = NULL;pq->size = 0;
}// 销毁队列 
void QueueDestroy(Que* pq)
{assert(pq);QNode* cur = pq->head;while (cur)             // 遍历释放结点 {QNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;pq->size = 0;
}// 入队列 
void QueuePush(Que* pq, QDataType x)
{assert(pq); // pq指针不能为空 QNode* newnode = (QNode*)malloc(sizeof(QNode)); // 申请新结点 if (newnode == NULL){perror("malloc fail");exit(-1);}// 初始化新结点中的成员 newnode->data = x;newnode->next = NULL;if (pq->tail == NULL)  // 入队列的结点是第一个结点 {pq->head = pq->tail = newnode;}else                   // 入队列的结点不是第一个结点 {pq->tail->next = newnode;pq->tail = newnode;}pq->size++;
}// 出队列
void QueuePop(Que* pq)
{assert(pq);assert(!QueueEmpty(pq));      // 出队列的时候,队列不能为空 if (pq->head->next == NULL)   // 只有一个结点的情况 {free(pq->head);pq->head = pq->tail = NULL;}else                          // 不止一个结点的情况 {QNode* next = pq->head->next;free(pq->head);pq->head = next;}pq->size--;
}// 取队头元素 
QDataType QueueFront(Que* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->head->data;
}// 取队尾元素 
QDataType QueueBack(Que* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}// 判空 
bool QueueEmpty(Que* pq)
{assert(pq);return pq->head == NULL;
}// 获取队列的大小 
int QueueSize(Que* pq)
{assert(pq);return pq->size;
}

 

相关文章:

手撕数据结构 —— 队列(C语言讲解)

目录 1.什么是队列 2.如何实现队列 3.队列的实现 Queue.h中接口总览 具体实现 结构的定义 初始化 销毁 入队列 出队列 取队头元素 取队尾元素 判断是否为空 获取队列的大小 4.完整代码附录 Queue.h Queue.c 1.什么是队列 队列是一种特殊的线性表&#xff0…...

Java知识巩固(五)

目录 基本数据类型 基本类型和包装类型的区别&#xff1f; 自动装箱与拆箱了解吗?原理是什么&#xff1f; 为什么浮点数运算的时候回邮精度丢失的风险&#xff1f; 如何解决浮点数运算的精度丢失问题&#xff1f; 超过 long 整型的数据应该如何表示&#xff1f; 基本数据…...

C# 中 yield关键字的使用

yield return有以下优点&#xff1a; 每次迭代时生成一个值&#xff0c;并且在下次迭代时继续从上次离开的地方开始。 延迟执行&#xff1a;只有在实际需要时才会生成下一个值&#xff0c;这对于处理大量数据非常有用。 节省内存&#xff1a;不需要一次性将所有数据加载到内存中…...

YoloDotNet 的基本使用方法详解

文章目录 一、创建项目与引用库二、模型加载与初始化三、图像数据的处理与输入四、目标检测结果的获取与解析五、性能优化与参数调整一、创建项目与引用库 在使用 YoloDotNet 之前,首先需要在开发环境中创建一个新的项目。可以选择使用 Visual Studio 等开发工具,创建一个 C#…...

0x12 Dapr Dashboard configurations 未授权访问漏洞 CVE-2022-38817

参考: Dapr Dashboard configurations 未授权访问漏洞 CVE-2022-38817 | PeiQi文库 (wgpsec.org)免责声明 欢迎访问我的博客。以下内容仅供教育和信息用途: 合法性:我不支持或鼓励非法活动。请确保遵守法律法规。信息准确性:尽管我尽力提供准确的信息,但不保证其完全准确…...

Android activity 启动流程

Android activity 启动流程 本文主要记录下acitivty的启动流程. 1: Activity 我们都知道启动activity调用方法: startActivity(Intent intent)startActivity(Intent intent, Nullable Bundle options)startActivityForResult(RequiresPermission Intent intent, int reques…...

使用 Go 语言实现 WebSocket的核心逻辑

文章目录 WebSocket 简介时序图核心逻辑Client 结构与功能创建新客户端消息读取逻辑 (ReadPump)发送消息逻辑 (Send)客户端管理器 (ClientManager)WebSocket 处理器处理心跳与长连接 总结 本文将基于 Go 语言&#xff0c;通过使用 gorilla/websocket 库来实现一个简单的聊天应用…...

Linux下的杀毒软件介绍

Linux下的杀毒软件介绍 一、Linux杀毒软件的基本概念和作用二、Linux杀毒软件的选择三、Linux杀毒软件推荐四、Linux杀毒软件对应用进程的影响五、结论在当今数字化和网络化的环境中,保护计算机系统的安全至关重要。尽管Linux操作系统因其开源、稳定且相对安全的特性而较少受到…...

JSONP详解

JSONP&#xff08;JSON with Padding&#xff09;是一种非官方的协议&#xff0c;它允许在服务器端集成Script tags返回至客户端&#xff0c;通过JavaScript callback的形式实现跨域访问。以下是对JSONP的详细解释&#xff1a; 一、JSONP的背景与原理 背景&#xff1a; 由于浏…...

Leetcode—1115. 交替打印 FooBar【中等】(多线程)

2024每日刷题&#xff08;180&#xff09; Leetcode—1115. 交替打印 FooBar C实现代码 class FooBar { private:int n;sem_t fooSem;sem_t barSem;public:FooBar(int n) {this->n n;sem_init(&fooSem, 0, 1);sem_init(&barSem, 0, 0);}~FooBar() {sem_destroy(&…...

Visual Studio Code基础:使用debugpy调试python程序

相关阅读 VS codehttps://blog.csdn.net/weixin_45791458/category_12658212.html?spm1001.2014.3001.5482 一、安装调试器插件 在VS code中可以很轻松地调试Python程序&#xff0c;首先需要安装Python调试器插件&#xff0c;如图1所示。 图1 安装调试器插件 Python Debugge…...

超全!一文详解大型语言模型的11种微调方法

导读&#xff1a;大型预训练模型是一种在大规模语料库上预先训练的深度学习模型&#xff0c;它们可以通过在大量无标注数据上进行训练来学习通用语言表示&#xff0c;并在各种下游任务中进行微调和迁移。随着模型参数规模的扩大&#xff0c;微调和推理阶段的资源消耗也在增加。…...

C 主要函数解析

1、fseek 函数 int fseek(FILE *stream, long offset, int fromwhere); 第一个参数stream为文件指针 第二个参数offset为偏移量&#xff0c;正数表示正向偏移&#xff0c;负数表示负向偏移 第三个参数origin设定从文件的哪里开始偏移,可能取值为&#xff1a;SEEK_CUR、 SEE…...

vue3学习:数字时钟遇到的两个问题

在前端开发学习中&#xff0c;用JavaScript脚本写个数字时钟是很常见的案例&#xff0c;也没什么难度。今天有时间&#xff0c;于是就用Vue的方式来实现这个功能。原本以为是件非常容易的事&#xff0c;没想到却卡在两个问题上&#xff0c;一个问题通过别人的博文已经找到答案&…...

吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)3.7-3.8

目录 第四门课 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;第三周 目标检测&#xff08;Object detection&#xff09;3.7 非极大值抑制&#xff08;Non-max suppression&#xff09;3.8 Anchor Boxes 第四门课 卷积神经网络&#xff08;Convolutional…...

【Linux】最基本的字符设备驱动

前面我们介绍到怎么编译出内核模块.ko文件&#xff0c;然后还加载了这个驱动模块。但是&#xff0c;那个驱动代码还不完善&#xff0c;驱动写好后怎么在应用层使用也没有介绍。 字符设备抽象 Linux内核中将字符设备抽象成一个具体的数据结构&#xff08;struct cdev&#xff…...

利用 Llama 3.1模型 + Dify开源LLM应用开发平台,在你的Windows环境中搭建一套AI工作流

文章目录 1. 什么是Ollama&#xff1f;2. 什么是Dify&#xff1f;3. 下载Ollama4. 安装Ollama5. Ollama Model library模型库6. 本地部署Llama 3.1模型7. 安装Docker Desktop8. 使用Docker-Compose部署Dify9. 注册Dify账号10. 集成本地部署的 Llama 3.1模型11. 集成智谱AI大模型…...

Docker常用命令分享二

docker的用户组管理过程&#xff1a; 1、sudo : 可以让普通用户临时获得root用户的权限&#xff0c;来新建docker用户组 2、普通用户并没有使用sudo的权限 3、先要让root用户把testing用户加入到sudoers的授权文件中 4、sudoers的文件居然是只读的&#xff0c;先解决这个问…...

【一步步开发AI运动小程序】二十、AI运动小程序如何适配相机全屏模式?

引言 受小程序camera组件预览和抽帧图像不一致的特性影响&#xff0c;一直未全功能支持全屏模式&#xff0c;详见本系列文件第四节小程序如何抽帧&#xff1b;随着插件在云上赛事、健身锻炼、AI体测、AR互动场景的深入应用&#xff0c;各开发者迫切的希望能在全屏模式下应用&am…...

[Java基础] 运算符

[Java基础] 基本数据类型 [Java基础] Java HashMap 的数据结构和底层原理 目录 算术运算符 比较运算符 逻辑运算符 位运算符 赋值运算符 其他运算符 常见面试题 Java语言支持哪些类型的运算符&#xff1f; 请解释逻辑运算符&&和&的区别? 请解释条件运…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...

ZYNQ学习记录FPGA(二)Verilog语言

一、Verilog简介 1.1 HDL&#xff08;Hardware Description language&#xff09; 在解释HDL之前&#xff0c;先来了解一下数字系统设计的流程&#xff1a;逻辑设计 -> 电路实现 -> 系统验证。 逻辑设计又称前端&#xff0c;在这个过程中就需要用到HDL&#xff0c;正文…...