数据结构·一篇搞定队列!

hello,大家好啊,肖恩又拖更了,你们听我狡辩,前段时间有期中考试,so我就没什么时间写这个,在这给大家道个歉😭😭😭
请添加图片描述
我后面一定尽力不拖更
那么接下来,我们来看队列这个数据结构

引言

队列是另一种常见的数据结构,它遵循"先进先出"(FIFO)的原则。队列通常用于存储等待处理的任务或数据,如任务调度、资源分配等。了解队列的基本概念和实现方式对于掌握算法和数据结构同样很重要。

队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出
FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头
在这里插入图片描述

队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数
组头上出数据,效率会比较低。
那我们下面来实现队列的一些操作
因为也不是很难,我直接附上代码

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType val;
}QNode;typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;
//初始化
void QueueInit(Queue* pq) {assert(pq);pq->phead = pq->ptail = NULL;pq->size = 0;
}
//销毁
void QueueDestroy(Queue* pq) {assert(pq);QNode* cur = pq->phead;while (cur) {QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail == NULL;pq->size = 0;
}// 队尾插入
void QueuePush(Queue* pq, QDataType x) {assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;
}newnode->next = NULL;newnode->val = x;if (pq->phead == NULL)pq->phead = pq->ptail = newnode;elsepq->ptail->next = newnode;pq->ptail = newnode;pq->size++;
}
// 队头删除
void QueuePop(Queue* pq) {assert(pq);assert(pq->size != 0);if (pq->phead->next = NULL) {free(pq->phead);pq->phead = pq->ptail = NULL;}else {QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}pq->size--;
}// 取队头和队尾的数据
QDataType QueueFront(Queue* pq) {assert(pq && pq->phead);return pq->phead->val;
}QDataType QueueBack(Queue* pq) {assert(pq && pq->ptail);return pq->ptail->val;
}
// 获取队列中有效元素个数
int QueueSize(Queue* pq) {assert(pq);return pq->size;
}
// 检测队列是否为空
bool QueueEmpty(Queue* pq) {assert(pq);return pq->size == 0;
}

简单说两个主要的操作

  1. 队尾插入 (QueuePush):

    • 首先检查传入的队列指针是否为空,如果为空则抛出错误。
    • 分配一个新的节点内存空间。
    • 将新节点的 next 指针设置为 NULL,并将待插入的数据 x 存储到节点的 val 字段。
    • 如果队列为空,则将新节点同时设置为头指针 phead 和尾指针 ptail
    • 否则,将当前尾节点的 next 指针指向新节点,并更新尾指针 ptail 指向新节点。
    • 最后将队列大小 size 加 1。
  2. 队头删除 (QueuePop):

    • 首先检查传入的队列指针是否为空,如果为空则抛出错误。
    • 检查队列是否为空,如果为空则什么也不做直接返回。
    • 如果队列只有一个节点,则释放该节点并将头尾指针都设置为 NULL
    • 否则,获取头节点的下一个节点,释放头节点,并将头指针 phead 指向下一个节点。
    • 最后将队列大小 size 减 1。

通过这两个基本操作,我们可以实现一个基于链表的队列数据结构,支持向队列尾部添加元素和从队列头部删除元素的功能。

实际中我们有时还会使用一种队列叫循环队列。环形队列可以使用数组实现,也可以使用循环链表实现。
使用循环队列的优点是可以高效地利用数组空间,避免了普通队列在删除元素时,需要移动所有剩余元素的问题。但同时也需要额外维护头尾指针,增加了一定的复杂度。

循环队列在某些场景下,如缓存管理、生产者-消费者模型等,能够发挥出较好的性能表现。
那么下面的一个面试题(也是考研题)就让我们来看看循环队列。

例题

设计循环队列
在这里插入图片描述

使用动态数组很方便
我相信下面详细的注释能让你明白循环队列是怎么回事,不是很理解的话,可以自己画图来便于理解

// 定义循环队列结构体
typedef struct {int *a;  // 存储队列元素的动态数组int head; // 队头下标int tail; // 队尾下标int k;    // 队列最大容量
} MyCircularQueue;// 检查队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue *obj) {return obj->head == obj->tail; // 当 head 和 tail 相等时,队列为空
}// 检查队列是否已满
bool myCircularQueueIsFull(MyCircularQueue *obj) {return (obj->tail + 1) % (obj->k + 1) == obj->head; // 当 (tail + 1) % (k + 1) 等于 head 时,队列已满
}// 创建一个容量为 k 的循环队列
MyCircularQueue *myCircularQueueCreate(int k) {MyCircularQueue *p = (MyCircularQueue *)malloc(sizeof(MyCircularQueue)); // 分配 MyCircularQueue 结构体的内存p->a = (int *)malloc((k + 1) * sizeof(int));    // 分配存储元素的动态数组p->k = k;                   // 设置队列最大容量p->head = p->tail = 0;  // 初始化 head 和 tail 为 0return p;
}// 向队列中添加一个元素
bool myCircularQueueEnQueue(MyCircularQueue *obj, int value) {if (myCircularQueueIsFull(obj))  // 如果队列已满,返回 falsereturn false;obj->a[obj->tail] = value;  // 将元素添加到队尾obj->tail = (obj->tail + 1) % (obj->k + 1); // 更新 tail 下标,实现循环return true;}// 从队列中删除一个元素
bool myCircularQueueDeQueue(MyCircularQueue *obj) {if (myCircularQueueIsEmpty(obj)) { // 如果队列为空,返回 falsereturn false;} else {obj->head = (obj->head + 1) % (obj->k + 1); // 更新 head 下标,实现删除队头元素return true;}
}// 获取队头元素
int myCircularQueueFront(MyCircularQueue *obj) {if (obj->tail == obj->head) { // 如果队列为空,返回 -1return -1;} else {return obj->a[obj->head]; // 返回队头元素}
}// 获取队尾元素
int myCircularQueueRear(MyCircularQueue *obj) {if (obj->tail == obj->head) { // 如果队列为空,返回 -1return -1;} else {return obj->a[(obj->tail + obj->k) % (obj->k + 1)]; // 返回队尾元素}
}// 释放循环队列占用的内存空间
void myCircularQueueFree(MyCircularQueue *obj) {free(obj->a); // 释放存储元素的动态数组free(obj);     // 释放 MyCircularQueue 结构体
}

循环队列的存储空间为 Q(1:100) ,初始状态为 front=rear=100 。经过一系列正常的入队与退队操作
后, front=rear=99 ,则循环队列中的元素个数为( )
A. 1
B. 2
C. 99
D. 0或者100

现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N。其队内有效长度为?(假设
队头不存放数据)
A. (rear - front + N) % N + 1
B. (rear - front + N) % N
C. (rear - front) % (N + 1)
D. (rear - front + N) % (N - 1)

解析:
在循环队列中,队头指针 front 指向队首元素的下一个位置(如果队头不存放数据),而队尾指针 rear 指向队尾元素的下一个位置。这意味着当队列为空时,front 和 rear 通常指向同一个位置(或者在某些实现中,rear 可能在 front 的下一个位置,具体取决于如何定义“空”状态)。

队列的有效长度(即队列中元素的数量)可以通过计算 rear 和 front 之间的差值来得到,但是需要注意这是一个循环结构,所以差值需要用模运算 % N 来处理。

假设 front 和 rear 的初始值都是 0(队列为空),并且每次入队操作 rear 会递增,每次出队操作 front 会递增,那么队列的有效长度可以用以下公式计算:

(rear - front + N) % N
这里加 N 是为了确保在 rear 小于 front 的情况下(即队列绕了一圈之后),差值仍然是正数。然后取模 N 来得到一个 0 到 N-1 之间的值,这个值就是队列的有效长度。

注意:这个公式假设 front 和 rear 的初始值都是 0,并且每次操作后都会递增。如果初始值不是 0,或者有其他特殊的入队/出队逻辑,那么可能需要调整这个公式。
那么到这里,基本上队列的东西都讲完啦
在这里插入图片描述
下一篇讲队列和栈的相互实现~~~
待会儿见
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/15882.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Greenplum使用hbase外部表

概述 GP可以通过pxf协议上的hbase外表功能&#xff0c; 在数据库中创建外部表&#xff0c;映射hbase table&#xff0c;以直接在gp中访问 hbase数据&#xff0c;方便将hbase的查询结果集保留在gp中 hbase端准备 HBase基础概念&#xff1a; •HBase 列包含两个组件&#xff1…

粒子辐照环境中相机镜头防护及LabVIEW图像处理注意事项

在粒子辐照环境测试电路板性能的实验中&#xff0c;需要对相机镜头进行有效防护&#xff0c;同时利用LabVIEW进行图像识别和处理。本文将讨论相机镜头防护的关键因素和LabVIEW处理过程中的注意事项&#xff0c;包括防辐射材料选择、辐射屏蔽措施、散热管理、空间布局及LabVIEW软…

c++11:左值引用和右值引用《全家桶》

总结一下C11中涉及到左值引用和右值引用的场景。 1 左值引用和右值引用的区别 左值引用 定义&#xff1a;对左值的引用。目的是避免内存拷贝&#xff0c;类似c中的指针,两个场景&#xff1a;函数传参、函数返回值。 右值引用 定义&#xff1a;对右值的引用。两个场景&#…

【机器学习-k近邻算法-01】 | Scikit-Learn工具包进阶指南:机器学习sklearn.neighbors模块之k近邻算法实战

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

骑行 - 新区永旺出发的环太湖路线

环过好几次太湖&#xff0c;但对路线都没太在意&#xff0c;都是跟着别人走的。这次自己制定一个路书&#xff0c;方便下次自己一个人环太湖时使用。 开始是使用高德地图做路书&#xff0c;只能在PC上做。我用的是网页版&#xff0c;每次选点太麻烦了。要输入地址搜索&#xff…

开源博客项目Blog .NET Core源码学习(27:App.Hosting项目结构分析-15)

本文学习并分析App.Hosting项目中后台管理页面的角色管理页面。   角色管理页面用于显示、检索、新建、编辑、删除角色数据同时支持按角色分配菜单权限&#xff0c;以便按角色控制后台管理页面的菜单访问权限。角色管理页面附带一新建及编辑页面&#xff0c;以支撑新建和编辑…

电缆厂可视化:提升生产透明度与运营效率

图扑电缆厂可视化系统通过实时监控和数据分析&#xff0c;提高生产过程的透明度和可控性&#xff0c;优化资源配置和质量管理&#xff0c;显著提升运营效率和产品质量。

启动SpringBoot项目及解决端口占用问题(指令版)

打包SpringBoot 项目 需要将 SpringBoot 项目进行打包。可以使用 Maven 的快捷工具&#xff0c;或者在项目的 pom.xml 文件所在目录执行以下命令&#xff1a; mvn clean package部署注意 Windows系统下&#xff0c;按照以下方式在cmd窗口以管理员身份允许使用命令启动spring…

Flutter 中的 StatefulBuilder 小部件:全面指南

Flutter 中的 StatefulBuilder 小部件&#xff1a;全面指南 在Flutter中&#xff0c;StatefulBuilder是一个高效的小部件&#xff0c;它根据给定的构建函数来构建widget&#xff0c;并在组件树中只对需要重新构建的部分进行更新。这使得它在性能优化方面非常有用&#xff0c;特…

电子电器架构 - AUTOSAR ON THE AIR

电子电器架构 - AUTOSAR ON THE AIR 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己…

Mybase长久破解

1、软件下载好之后&#xff0c;找到文件mybase8.ini文件 2、使用记事本打开&#xff0c;通过 Ctrl F 输入快速找到属性设置FirstUseOn.UserLic.App&#xff0c;将等号后面的数值删掉保存即可 3、使用防护中心–>自定义防护&#xff08;记得开启&#xff09; 4、添加规则…

Golang文件操作

文章目录 文件操作基本介绍普通的文件操作方式&#xff08;os包&#xff09;带缓冲的文件操作方式&#xff08;bufio包&#xff09;文件拷贝操作&#xff08;io包&#xff09; 命令行参数基本介绍解析命令行参数&#xff08;flag包&#xff09; JSON基本介绍JSON序列化JSON反序…

【MySQL精通之路】MySQL的使用(3)-连接到服务器的配置

目录 1.连接建立的命令选项 1.1.--default-auth 1.2.--hosthost_name, -h host_name 1.3.--password[pass_val], -p[pass_val] 1.4.--password1[pass_val] 1.5.--password2[pass_val] 1.6.--password3[pass_val] 1.7.--pipe, -W 1.8.--plugin-dirdir_name 1.9.--port…

【YOLOv10训练】:报错 AttributeError: ‘str‘ object has no attribute ‘view‘ 解决方法

YOLOv10训练报错 YOLOv10是在YOLOv8基础上修改的&#xff0c;即&#xff1a;训练方法和过程是相同的。 但按照v8训练程序train.py&#xff0c;如下所示&#xff0c;直接训练&#xff1a; from ultralytics import YOLO# Load a model model YOLO("ultralytics/cfg/mod…

真拿AI赚到钱的人,不在朋友圈里

1 最近有张两大AI巨头对比的梗图给我看乐了&#xff0c;玩儿AI的还在做产品&#xff0c;玩儿焦虑的已经在数钱了。 这也是在做AI&#xff0c;只不过是唉声叹气的ai。 要我说&#xff0c;现在缺的根本不是AI&#xff0c;而是【有用的AI】。 恩格斯老师说过一句话&#xff1a…

科林Linux6_网络

#include<sys/socket.h> #include<arpa/inet.h> //大小端转换 #include<netdb.h> //DNS一、Socket套接字 为了开发网络应用&#xff0c;系统提供一套API函数接口&#xff0c;用于网络应用开发&#xff0c;这些接口称为套接字函数 struct sockaddr_in…

数据库管理-第194期 网络加速RDMA初探(20240526)

数据库管理194期 2024-05-26 数据库管理-第194期 网络加速RDMA初探&#xff08;20240526&#xff09;1 概念2 发展3 使用总结 数据库管理-第194期 网络加速RDMA初探&#xff08;20240526&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#xff08;尹海文&#xff09; Oracle ACE A…

英文 海量的学习句子比单独的记单词效果要好,格句致知。

英文 海量的学习句子比单独的记单词效果要好 句子有上下文、场景和时态等&#xff0c;能形成剧情&#xff0c;变得生动有趣。 如果一句没听懂&#xff0c;还继续听就是浪费时间了。要一句一句地深究&#xff0c;不然就要读好几遍&#xff0c;还得背诵。要深入理解&#xff0c…

不同的二叉搜索树(II)题解

toc &#x1f91a;我的博客 欢迎光临我的博客&#xff1a;https://blog.csdn.net/qq_52434217?typeblog &#x1f95b;前言 动态规划是常见的算法思路&#xff0c;动态规划在计算过程中保存了部分计算结果到内存中&#xff0c;以便于在进行下一次计算时可以直接从内存中获…

Ubuntu部署Dolphinscheduler单机版并配置PG数据库

1、下载并解压Dolphinscheduler DolphinScheduler | 下载 (apache.org) 下载完成后得tar.gz包 下载稳定版 下载稳定版 下载稳定版 tar -zxvf apache-dolphinscheduler-3.1.9-alpha-bin.tar.gz mv apache-dolphinscheduler-3.1.9-alpha-bin dolphinscheduler-bin cd dolph…