数据结构--队列与循环队列的实现

数据结构–队列的实现

1.队列的定义

比如有一个人叫做张三,这天他要去医院看病,看病时就需要先挂号,由于他来的比较晚,所以他的号码就比较大,来的比较早的号码就比较小,需要到就诊窗口从小号到大依次排队,前面的小号就诊结束之后,才会轮到大号来,小号每就诊完毕就销毁,每新来一个病人就会顺着向后增加一个较大的号码,这些号码就构成了队列.

所谓队列就是一种先进先出的数据结构,例如在例子中,先来挂号的病人先就诊,后来的病人后就诊,队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表,队列是一种先进先出的线性表,允许插入数据的一端称之为队尾,允许删除数据的一端称之为队头.**假设队列中的元素是{a,b,c,d,e,f,g}那么a就是队头元素,g就是队尾元素,这样删除时就可以总是从a处开始,插入数据时从g开始,也比较符合我们的日常生活习惯.

在这里插入图片描述

队列在生活中的使用非常频繁.

2.队列的实现

队列实际上也是线性表,但是队列的操作与栈是不同的,队列的对于数据的插入操作是在队尾进行的,对数据的删除操作是在队头进行,那么由此可以想到,对于有这种特点的队列,使用链表的结构更加方便,因为链表的头删和尾插的效率非常高,不需要像数组那样挪动数据.

2.1节点的定义

每个节点需要存储数据和下一个节点的地址.

typedef struct QueueNode//此处定义的是每个节点的结构
{struct QueueNode* next;QDataType data;
}QueueNode;

由于我们是对每个节点之间的链接关系进行处理,所以就需要定义结构体的指针对节点中的next指针进行操作,所以我们可以定义head和tail两个结构体指针,head指针指向链表的第一个节点,tail指针指向链表的最后一个节点.那么就可以将这两个节点也包装成一个结构体:

typedef struct Queue//将两个指针包装成一个结构体
{QueueNode* head;QueueNode* tail;
}Queue;

在这里插入图片描述

2.2队列的初始化

void QueueInit(Queue* pq)//初始化队列
{assert(pq != NULL);pq->head = NULL;pq->tail = NULL;
}

2.3判断队列是否为空

bool QueueEmpty(Queue* pq)
{assert(pq);return pq->head == NULL;
}

2.4队列的销毁

void QueueDestroy(Queue* pq)
{assert(pq);QueueNode* cur = pq->head;//while (cur != NULL){QueueNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;
}

2.5插入数据

void QueuePush(Queue* pq, QDataType x)//插入数据
{assert(pq);QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL){printf("malloc fail!");exit(0);}newnode->data = x;newnode->next = NULL;if (pq->head == NULL){pq->head = pq->tail = newnode;}else{pq->tail->next = newnode;//连接两个节点pq->tail = newnode;//新的尾节点}
}

2.6删除队头数据

删除队头数据之前要判断队列是否为空队列,如果队列是空队列就无法进行删除操作.

void QueuePop(Queue* pq)//删除数据
{assert(!QueueEmpty(pq));//队列不能为空QueueNode* next = pq->head->next;free(pq->head);pq->head = next;//假如链表已经被删完了,此刻要将tail也置为空指针if (pq->head == NULL){pq->tail = NULL;}
}

2.7取出队尾数据

QDataType QueueBack(Queue* pq)//取出队尾的数据
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}

2.8取出队头数据

QDataType QueueFront(Queue* pq)//获取头的数据
{assert(pq);assert(!QueueEmpty(pq));return pq->head->data;
}

2.9获取队列的节点的个数

int QueueSize(Queue* pq)
{assert(pq);int n = 0;QueueNode* cur = pq->head;while (cur != NULL){n++;cur = cur->next;}return n;
}

3.循环队列

3.1循环队列的设计

  1. 假定我们是使用的数组实现队列.那么假设一个队列含有n个元素,我们就需要创建一个元素个数大于n的数组.并将队列中的数据存储在数组的前n个单元,数组下标为0的一端就是队头,另一端就是队尾.
  2. 为了方便,我们设置两个变量,一个front用于存储队头数据的下标,也就是0,另一个rear变量用于存储队尾的元素的下一个位置.当需要取出队头元素时,就需要除了队头之外的所有数据都需要向前移动一格.

在这里插入图片描述

  • 由此看来,效率是不高的,所以这里可以改进,让front指针移动起来,队头每出一个元素,front就向后移动一个单位.

在这里插入图片描述

  • 假设数组一开始是空的,那么front和rear一开始的值就都是0,每插入一个元素,rear就向后移动.

在这里插入图片描述

  • 但是此时的rear就移动到了数组之外的空间了,假如此刻数组中的数据都已经满了,然而继续向其中插入数据,就出现了越界问题.

假如是以下这种情况呢??
在这里插入图片描述

  • 此刻向rear位置插入数据之后,此时的数组的0和1位置处是空的,那此时rear若再向后加,就显得有点蠢了,因为数组中的前面是空着的却不用.

解决办法:当rear快越界时,接着让rear从数组的第一个元素开始,构成循环,这就是循环队列.例如在下面这种情况,将rear改为0时比较好的.
在这里插入图片描述

那此刻我们接着向队列中插入元素.
在这里插入图片描述

  • 不难发现,当队列满了之后,rear和front是指向同一个下标的(即rear == front).在队列为空时,rear和front指向的是同一个下标(rear == front),那么什么情况队列是满什么情况队列是空就无法确切的判断了.

解决方案:当队列为空时,条件是rear == front,当队列为满时,保留一个元素的空间,在数组中留一个空闲单元,如下图所示,此刻的队列就已经满了.假设数组的最大容量是N个单位,那么队列为满的条件就是 (rear+1)%N == front.
在这里插入图片描述

由此可推断出:在容量为N的数组中,存储的元素个数为:(rear-front+N)%N

3.2循环队列的元素的创建

这里定义一个MAX常量用于记录队列中的元素个数,实际上的数组需要MAX个单位的空间.

typedef int QDataType;
typedef struct Queue {QDataType a[MAX+1];int front;int rear;
}Queue;

3.3循环队列的初始化

//队列的初始化
void InitQueue(Queue* q)//含有MAX个元素的队列,开辟MAX+1个单位空间
{q->front = q->rear = 0;
}

3.4取出队头元素

//出队列
QDataType DeQueue(Queue* q)
{assert(!QueueEmpty(q));QDataType ret = q->a[q->front];q->front = (q->front + 1) % (MAX + 1);return ret;
}

3.5向队尾插入元素

//入队列
void EnQueue(Queue* q, QDataType* x)
{assert(!QueueFull(q));q->a[q->rear] = x;q->rear = (q->rear + 1) % (MAX + 1);
}

3.6队列中存储的元素个数

//队列的元素个数
int QueueSize(Queue* q)
{return (q->rear - q->front + MAX + 1) % (MAX + 1);
}

3.7判断队列是否为空

//判断队列是否为空
bool QueueEmpty(Queue* q)
{return q->front == q->rear;
}

3.8判断队列是否为满

bool QueueFull(Queue* q)
{return (q->rear + 1) % (MAX + 1) == q->front;
}

4.链式队列和循环队列的比较

循环队列是事先申请好空间,使用期间无法释放,而链式队列则不存在这个问题.虽然链式队列在空间上会有更多的开销,但是也在可接受范围之内.所以在空间上,链式队列更加灵活.

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java的火车高铁订票购票系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

支持向量机SVM:从数学原理到实际应用

目录 一、引言背景SVM算法的重要性 二、SVM基础线性分类器简介什么是支持向量?超平面和决策边界SVM的目标函数 三、数学背景和优化拉格朗日乘子法(Lagrange Multipliers)KKT条件核技巧(Kernel Trick)双重问题和主问题&…

【云备份】

文章目录 [toc] 1 :peach:云备份的认识:peach:1.1 :apple:功能了解:apple:1.2 :apple:实现目标:apple:1.3 :apple:服务端程序负责功能:apple:1.4 :apple:服务端功能模块划分:apple:1.5 :apple:客户端程序负责功能:apple:1.6 :apple:客户端功能模块划分:apple: 2 :peach:环境搭建…

留住时光、固化时间、让一瞬成为永恒——全新的真人手办定制模式,就选易模小程序制作。

如何能永远留住一瞬间? 有人说我可以拍摄一张照片,照片的问世确实给生活中许多美好的瞬间留下了可以记录的工具。但是随着时间的流逝,照片终究也会泛黄,似乎有一些记忆的温度,有一些岁月的棱角,也是照片所给…

SD卡格式化怎么恢复?

随着智能手机、平板电脑、数码相机和行车记录仪等各种移动电子设备走入千家万户,SD卡作为与这些设备相配套的存储介质,也随之获得了广泛的市场认可。SD卡因其体积小巧、容量庞大、读写速度高及与多种设备兼容的优点,逐渐成为日常工作和生活中…

怒刷LeetCode的第23天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一:贪心算法 方法二:动态规划 方法三:回溯算法 方法四:并查集 第二题 题目来源 题目内容 解决方法 方法一:排序和遍历 方法二:扫描线算法 方法…

StarRocks数据导入

1、相关环境 Flink作为当前流行的流式计算框架,在对接StarRocks时,若直接使用JDBC的方式"流式"写入数据,对StarRocks是不友好的,StarRocks作为一款MVCC的数据库,其导入的核心思想还是"攒微批降频率&qu…

HTTP协议,请求响应

、概述 二、HTTP请求协议 三、HTTP响应协议 四、请求数据 1.简单实体参数 RequestMapping("/simpleParam")public String simpleParam(RequestParam(name "name" ,required false ) String username, Integer age){System.out.println (username "…

车牌文本检测与识别:License Plate Recognition Based On Multi-Angle View Model

论文作者:Dat Tran-Anh,Khanh Linh Tran,Hoai-Nam Vu 作者单位:Thuyloi University;Posts and Telecommunications Institute of Technology 论文链接:http://arxiv.org/abs/2309.12972v1 内容简介: 1)方向&#x…

可以动态改变刻度背景色的车速仪表盘

最近做的项目的主页面需要用到一个仪表盘来动态显示车速,同时改变对应的背景色 仪表盘 开始是想着使用echarts,修修改改拿来用,但是人家客户有规定,必须搞个差不多的,那没办法,自 己动手搞个吧 截图如下&am…

多源最短路径的原理及C++实现

时间复杂度 O(n3),n是端点数。 核心代码 template<class T, T INF 1000 * 1000 * 1000> class CNeiBoMat { public: CNeiBoMat(int n, const vector<vector<int>>& edges,bool bDirectfalse,bool b1Base false) { m_vMat.assign(n, vector<…

2023年【R2移动式压力容器充装】模拟考试及R2移动式压力容器充装模拟考试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 R2移动式压力容器充装模拟考试考前必练&#xff01;安全生产模拟考试一点通每个月更新R2移动式压力容器充装模拟考试题题目及答案&#xff01;多做几遍&#xff0c;其实通过R2移动式压力容器充装操作证考试很简单。 1…

MySQL5.7版本与8.0版本在Ubuntu(WSL环境)系统安装

目录 前提条件 1. MySQL5.7版本在Ubuntu&#xff08;WSL环境&#xff09;系统安装 1. 1 下载apt仓库文件 1.2 配置apt仓库 1.3 更新apt仓库的信息 1.4 检查是否成功配置MySQL5.7的仓库 5. 安装MySQL5.7 1.6 启动MySQL 1.7 对MySQL进行初始化 1.7.1 输入密码 …

PDF文件压缩软件 PDF Squeezer mac中文版​软件特点

PDF Squeezer mac是一款macOS平台上的PDF文件压缩软件&#xff0c;可以帮助用户快速地压缩PDF文件&#xff0c;从而减小文件大小&#xff0c;使其更容易共享、存储和传输。PDF Squeezer使用先进的压缩算法&#xff0c;可以在不影响文件质量的情况下减小文件大小。 PDF Squeezer…

排序算法之【快速排序】

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

[sping] spring core - 依赖注入

[sping] spring core - 依赖注入 所有代码实现基于 Spring Boot3&#xff0c;core 的概念很宽广&#xff0c;这里的 core concept 主要指的就是 Inversion of Control 和 Dependency Injection&#xff0c;其他的按照进度应该是会被放到其他的 section 记录 之前有写过 IoC 和…

MARS: An Instance-aware, Modular and Realistic Simulator for Autonomous Driving

MARS: An Instance-aware, Modular and Realistic Simulator for Autonomous Driving&#xff08;基于神经辐射场的自动驾驶仿真器&#xff09;https://github.com/OPEN-AIR-SUN/marshttps://arxiv.org/pdf/2307.15058.pdfhttps://mp.weixin.qq.com/s/6Ion_DZGJwzs8JOoWMMbPw …

Ubuntu基于Docker快速配置GDAL的Python、C++环境

本文介绍在Linux的Ubuntu操作系统中&#xff0c;基于Docker快速配置Python与C 这2种不同编程语言可用的地理数据处理库GDAL开发环境的方法。 本文就将Python与C 这2种不同编程语言的GDAL模块配置方法分开来介绍&#xff0c;大家依据自己的需求来选择即可——但无论是哪种方法&a…