【数据结构】 队列详解!庖丁解牛般细致讲解!

news/2024/10/18 3:25:29/

在这里插入图片描述

🎥 屿小夏 : 个人主页
🔥个人专栏 : 数据结构解析
🌄 莫道桑榆晚,为霞尚满天!

文章目录

  • 📑前言
  • 🌤️队列的概念剖析
    • ☁️什么是队列
    • ☁️队列的特性
    • ☁️队列的图解
  • 🌤️队列的详细实现
    • ☁️队列不同的实现方式
    • ☁️队列结构体
    • ☁️队列的初始化
    • ☁️入队列
    • ☁️出队列
    • ☁️获取对头元素
    • ☁️获取队尾元素
    • ☁️队列的判空
    • ☁️队列有效的元素个数
    • ☁️队列的销毁
  • 🌤️队列的应用场景
  • 🌤️全篇总结

📑前言

什么是队列?队列有什么样的特性?它的应用场景有哪些?
本文会对队列这种数据结构进行进行庖丁解牛般的讲解,让你彻底学会数据结构!

🌤️队列的概念剖析

☁️什么是队列

队列是一种常见的数据结构,它按照先进先出(FIFO)的原则进行操作。队列中的元素按照进入的顺序排列,新元素插入到队列的一端,称为队尾,已有元素的删除操作则发生在队列的另一端,称为队头。

☁️队列的特性

  1. 先进先出(FIFO):队列中的元素按照进入的顺序排列,最先进入的元素最先被删除。
  2. 只能在队尾插入元素:新元素只能从队尾插入。
  3. 只能在队头删除元素:已有元素只能从队头删除。
  4. 队列长度可变:队列的长度可以根据需要动态变化。
  5. 队列可以为空:队列中没有元素时为空队列。
  6. 队列可以为满:队列中的元素数量达到了队列的最大容量时为满队列。

☁️队列的图解

在这里插入图片描述

这个可以简单理解成,就像是我们生活中的食堂打饭排队一样,先来的在前面后来的在后面,前面的打完饭后就走了。这就像是数据结构中的队列。

🌤️队列的详细实现

☁️队列不同的实现方式

  1. 数组实现:使用数组来存储队列中的元素,通过两个指针分别指向队头和队尾。入队操作时,将新元素插入到队尾,同时移动队尾指针;出队操作时,删除队头元素,同时移动队头指针。这种实现方式简单直观,但在动态扩容时需要进行数据的搬移,效率较低。
  2. 链表实现:使用链表来存储队列中的元素,每个节点包含一个元素和一个指向下一个节点的指针。入队操作时,创建一个新节点并插入到链表的末尾;出队操作时,删除链表的头节点。这种实现方式不需要进行数据的搬移,但需要额外的空间来存储指针。

本文我们的队列使用链表的形式来进行队列的实现。这里更推荐链表实现起来不会那么复杂。

在这里插入图片描述

☁️队列结构体

typedef int QDatatype;typedef struct Qlistnode
{struct Qlistnode* next;QDatatype data;
}Qlistnode;typedef struct Queue
{Qlistnode* fornt;Qlistnode* rear;int size;
}Queue;

对数据类型进行重命名,这样以后需要更换其他数据类型使用的时候只需要更改这一个地方就可以了。

​ 这里有两个结构体,进行了嵌套。定义一个链表的结点,包含当前结点元素和指向下一个结点的指针。然后定义一个队列结构体,队列中两个结构体体指针分别代表队头和队尾,size是当前队列的有效元素个数。

​ 这样做的目的是,方便了队列的头删(出队列)和尾插(入队列),已经获取队列内的元素个数和队尾、队头的元素。

☁️队列的初始化

void QueueInit(Queue* q)
{assert(q);q->fornt = NULL;q->rear = NULL;q->size = 0;
}

这里先将所以的指针都置空,size为0,因为是初始化所以队中无元素。

☁️入队列

在队列插入数据,要先开辟一个结点的空间,用来存放值和下一个结点的地址。这里要进行两种情况的判断:如果队头为空时,代表此时队列中无元素,那么队头和队尾指针指向同一块空间。当队头不为空时,就将队尾的指针指向新开辟的结点。插入新数据后,size的个数++。

在这里插入图片描述

void QueuePush(Queue* q, QDatatype x)
{assert(q);Qlistnode* newnode = (Qlistnode*)malloc(sizeof(Qlistnode));if (newnode == NULL){perror("malloc");exit(-1);}newnode->data = x;newnode->next = NULL;if (q->rear == NULL){q->fornt = q->rear = newnode;}else{q->rear->next = newnode;q->rear = newnode;}q->size++;
}

☁️出队列

在队头删除数据,此处和入队列一样,要进行两种情况的判断:

​ 如果队头和队尾指针同时指向一块空间时,此时队列中只有一个元素,所以释放队头或队尾指针都可,然后将队头和队尾指针置空,方便下一次进行插入数据(入队列)。

​ 队头和队尾指针不相等时,表名队列有最少一个以上的元素,创建一个临时结点用来存放队头指针下一个元素的地址,然后释放队头指针,再让队头指针指向下一个元素。

​ 出队列后,队列中的有效元素个数就少了一个,所以size也要进行–。

在这里插入图片描述

void QueuePop(Queue* q)
{assert(q);assert(!QueueEmpty(q));if (q->fornt == q->rear){free(q->fornt);q->fornt = NULL;q->rear = NULL;}else{Qlistnode* newnode = q->fornt->next;free(q->fornt);q->fornt = newnode;}q->size--;
}

☁️获取对头元素

要获取元素前需要进行判空,如果队列是空,那么就会报错。

队头指针指向的就是队列的首元素地址,进行解引用就可以获取队头的元素。

QDatatype QueueFornt(Queue* q)
{assert(q);assert(!QueueEmpty(q));return q->fornt->data;
}

☁️获取队尾元素

要获取元素前需要进行判空,如果队列是空,那么就会报错。

队头指针指向的就是队尾的首元素地址,进行解引用就可以获取队尾的元素。

QDatatype QueueRear(Queue* q)
{assert(q);assert(!QueueEmpty(q));return q->rear->data;
}

☁️队列的判空

队列如果为空的情况下代表队头指针是空,此时队列无元素。

bool QueueEmpty(Queue* q)
{assert(q);return q->fornt ==  NULL;
}

☁️队列有效的元素个数

我们先前定义的size就是队列中有效元素的个数。

int QueueSize(Queue* q)
{assert(q);return q->size;
}

☁️队列的销毁

因为队列是链表实现的,所以这里的释放空间要写成循环,释放队列中每一个结点的空间。

创建临时指针,让newnode去迭代。最后队头和队尾指针都置空,size归0。

void QueueDestroy(Queue* q)
{assert(q);Qlistnode* newnode = q->fornt;while (newnode){q->fornt = newnode->next;free(newnode);newnode = q->fornt;}q->fornt = q->rear = NULL;q->size = 0;
}

🌤️队列的应用场景

队列在计算机科学和软件开发中有广泛的应用场景:

  1. 任务调度:队列可以用来实现任务调度系统,将待执行的任务按照先后顺序排列,每次从队头取出一个任务进行执行,保证任务按照顺序执行。
  2. 消息传递:队列可以用来实现消息传递系统,消息发送方将消息入队,消息接收方从队头出队获取消息。这种方式可以实现异步消息传递,并且可以处理消息的积压情况。
  3. 缓冲区:队列可以用来实现缓冲区,例如网络数据传输中的数据包缓冲区、磁盘读写中的数据缓冲区等。数据可以按照顺序入队,然后按照顺序出队进行处理,保证数据的有序性和流畅性。
  4. 广度优先搜索:在图的广度优先搜索算法中,使用队列来存储待访问的节点,每次从队头取出一个节点进行访问,并将其邻接节点入队。这样可以保证按照层次遍历图的节点,从而实现广度优先搜索。
  5. 线程池:在多线程编程中,线程池可以使用队列来实现任务的调度。将待执行的任务入队,线程池中的线程从队头取出任务进行执行,保证任务的有序执行和线程的复用。

以上只是一些常见的应用场景,队列还可以用于解决其他问题,如数据流量控制、请求排队、打印队列等。队列的先进先出特性使其在这些场景下能够提供高效的数据处理和调度能力。

🌤️全篇总结

本篇对队列这种数据结构进行了概念的说明,对队列的实现细致入微,最后普及了队列这种数据结构的泛用性!

☁️ 好啦,由于篇幅有限,本章仅对队列进行了细致入微的讲解,后序还会有更多的数据结构文章分享哦!
看到这里了希望给博主留个:👍 点赞🌟收藏 ⭐️ 关注!
你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦。
在这里插入图片描述


http://www.ppmy.cn/news/1185653.html

相关文章

Power BI 傻瓜入门 17. 共享和Power BI工作区

本章内容包括: 设置与Power BI服务的共享和协作使用监控和性能工具加快业务运营通过查看数据联机排除数据故障 在经历了跨数据源的整个数据生命周期、构建可视化、了解DAX和发布报告之后,作为power BI的高级用户,您的下一步是与业务中的所有…

C语言KR圣经笔记 2.8自增和自减 2.9位运算 2.10赋值

2.8 自增和自减操作符 C提供了两个不同寻常的操作符,用于对变量进行自增和自减。自增操作符对操作数加上1,而自减操作符 -- 对操作数减去1。我们已经频繁使用 对变量进行自增,如: if (c \n)nl; 不寻常之处在于 和 -- 既能用作…

2023年中国冷风机分类、销量及市场规模分析[图]

冷风机通常是指一种设备,用于通过冷却空气来调节室内或工业环境的温度。这些设备通过循环空气并通过冷却元件(如冷却盘或冷凝器)来降低空气的温度,从而实现温度控制。冷风机在家庭、商业和工业领域都有广泛的应用,可以…

【项目实训】在线订餐系统(完整代码)

文章目录 一、实验目的二、实验内容三、实验步骤四、完整程序五、程序分析六、运行结果附:系列文章一、实验目的 会合理使用程序基本语法结构,包括变量、数据类型会使用顺序、分支、循环、跳转语句控制程序逻辑会使用数组操作字符串二、实验内容 设计一个在线订餐系统,编写…

记录CMake一键编译和生成的指令

cmake -S . -B build cmake --build build 假设当前在源代码根目录, 第一句话-S代表源代码根目录,-B指向生成中间文件的目录。 第二句话在build目录执行生成指令,会生成最后的可执行文件。 这两句话很实用,之前我总是记不住&am…

如何提升ERP的实施成功率?这5个阶段的重点要注意!

目录 花了70%预算的ERP系统, 只有30%的概率实施成功可不行! 鼎捷专家解惑:ERP实施别踩雷! ERP实施分阶段,重点清晰才好办 01 项目启动阶段工作重点 02 机制流程规划阶段工作重点 03 流程和数据验证重点 04 实施…

天气数据可视化平台-计算机毕业设计vue

天气变幻无常,影响着我们生活的方方面面,应用天气预报信息可以及时了解天气的趋势,给人们的工作、生活等带来便利,也可以为我们为未来的事情做安排和打算,所以一个精准的、易读 通过利用 程序对气象网站大量的气象信息…

【计算机网络】分层模型和应用协议

网络分层模型和应用协议 1. 分层模型 1.1 五层网络模型 网络要解决的问题是:两个程序之间如何交换数据。 四层?五层?七层? 2. 应用层协议 2.1 URL URL(uniform resource locator,统一资源定位符&#…