数据结构与算法:队列

这篇具有很好参考价值的文章主要介绍了数据结构与算法:队列。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在上篇文章讲解了栈之后,本篇也对这一章进行收尾,来到队列!

队列的介绍

队列(Queue)就像是排队买票的人群。想象一下你去电影院看电影,人们在售票窗口形成一条线(队列)等待购票。队列遵循一个很重要的原则:先来先服务(First In, First Out,简称FIFO)。这意味着最先到达并排队的人将会是第一个买到票并离开队列的人,随后到达的人则依次排在队伍的后面,等待买票。

客服服务应用了一种数据结构来实现刚才提到的先进先出的排队功能,这就是队列

队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表

队列是一种先进先出的线性表,允许插入的一端成为队尾,允许删除的一端称为队头

数据结构与算法:队列,数据结构与算法,数据结构

队列的存储结构

线性表有两种存储结构:顺序存储和链式存储,在栈中我们知道,栈存在两种存储结构,队列作为特殊的线性表,也同样存在这两种存储结构

队列顺序存储的不足之处

我们假设一个队列有n个元素,则顺序存储的队列需要建立一个大于n的数组,并把队列所有元素存储在数组的钱n个单元,数组下表为0的一端即为队头

此时入队列操作,其实就是在队尾追加一个元素,并不需要移动任何元素,时间复杂度为O(1).
数据结构与算法:队列,数据结构与算法,数据结构

与栈不同的是,队列元素的出列在队头,即下表为0的位置,意味着队列中所有元素都得向前移动。此时时间复杂度为O(N);
数据结构与算法:队列,数据结构与算法,数据结构
如果不去限制队列元素必须存储在数组前n个单元这一条件,出队的性能则会大大增加,即队头不需要一定要在下标为0的位置。
数据结构与算法:队列,数据结构与算法,数据结构
此时我们则需要设置队头指针为front,rear指针指向队尾元素的下一个位置

假设长度为5的数组,入队四个元素,rear指针指向下标为4的位置
数据结构与算法:队列,数据结构与算法,数据结构
出队a1,a2,此时front指向下标为2的位置,rear不变
数据结构与算法:队列,数据结构与算法,数据结构

当front与rear相等时则队列为空

如果我再入队a5,此时front不变,rear移动到数组之外,指向哪里了呢?
数据结构与算法:队列,数据结构与算法,数据结构

随着队列操作的进行,如果不断地添加和移除元素,队头指针会向数组的末尾移动,这可能会造成队头不在数组的起始位置。

当继续向队列中添加元素而队尾已经达到数组的最末端时,若不采取任何措施,就无法再添加新的元素,即使数组的前部(队头之前的部分)是空闲的。这种情况看起来好像数组已经“溢出”了,但实际上是因为未充分利用数组的空间,称为“假溢出”。

循环队列的定义

所以我们如何解决上述的假溢出呢?

解决假溢出的办法就是后面满了,再从头开始,头尾相接的循环,把队列这种头尾相接的顺序结构称为循环队列

顺着上述例子,当a5入队后,rear可以改为指向下标0,则解决了指针指向不明

数据结构与算法:队列,数据结构与算法,数据结构
接着入队a6,将它置于下标为0处,rear指向下标为1处

数据结构与算法:队列,数据结构与算法,数据结构
上述提到,空队列时,front等于rear,若我插入a7,此时front等于rear,如何判断此时的队列是满还是空呢?
数据结构与算法:队列,数据结构与算法,数据结构
解决办法:
我们让队列判空条件还是front=rear,当队列满时,我们修改条件,使其保留一个元素空间,也就是队列满时,还有一个空闲单元
数据结构与算法:队列,数据结构与算法,数据结构
rear可能比front大,也可能比front小,相差一个位置即为满
设队列的最大尺寸为QueueSize,则队列满的条件是
(rear+1)%QueueSize==front

这种顺序存储若不是循环队列,算法性能不高,循环队列又面临着数组溢出的问题,我们接下来讲解队列的链式存储结构**

队列的链式存储结构

队列的链式存储结构,就是线性表的单链表,只不过它只能尾进头出

我们在链队列中有两个指针,一个指向头,一个指向尾

链队列的构建

typedef int QDataType;
typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;
typedef struct Queue 
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

这里的队列是通过链表实现的,链式存储方式的好处在于它可以动态地分配内存,避免了顺序队列中可能发生的假溢出问题,同时也不需要在队列初始化时就确定其最大容量。

  • phead指针指向队列的头部(第一个元素),而ptail指针指向队列的尾部(最后一个元素)。这两个指针是实现队列基本操作(如入队和出队)的关键

  • size成员存储队列中当前的元素数量。这个信息对于快速获取队列的大小,以及确定队列是否为空等操作非常有用。

链队列的初始化

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size=0;
}

在封装的Queue结构体背景下,通过QueueInit(Queue* pq)函数以指针形式传递
传递指向Queue结构体的指针允许QueueInit函数直接对实例进行初始化操作,包括设置头尾指针为NULL和队列大小为0。

队尾入队

只有入队时需要创造新节点,这里我们直接在函数里完成新节点的构造,不需要单独的函数

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->val = x;
	newnode->next = NULL;

	if (pq->ptail == NULL)
	{
		pq->ptail = pq->phead = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}
  • 如果队列为空(即pq->ptail为NULL),则新节点既是队列的头节点也是尾节点,因此将pq->phead和pq->ptail都指向新节点。
  • 如果队列不为空,则将当前尾节点的next指针指向新节点,然后更新pq->ptail指向新节点,这样新节点就成为了队列的尾节点。
  • 将队列的size成员加1,表示队列中元素的数量增加

队头出队

void QueuePop(Queue* pq) {
	assert(pq);                     
	if (pq->phead == NULL) return;  
	QNode* temp = pq->phead;        
	pq->phead = pq->phead->next;  
	free(temp);                    

	temp = NULL;
	if (pq->phead == NULL) {      
		pq->ptail = NULL;
	}

	pq->size--;  
}
  • if (pq->phead == NULL) return;如果队列为空,则没有元素可以弹出
  • 构建temp中间变量来指向要释放的节点,将头结点指向下一个节点
  • 如果弹出之后队列变为空,则尾指针也要更新为 NULL

获取队头队尾元素

QDataType QueueFront(Queue* pq)
{
	assert(pq);                     // 确保 pq 不是 NULL
	assert(pq->phead != NULL);
	return pq->phead->val; 

}
QDataType QueueBack(Queue* pq) {
	assert(pq != NULL); // 确保队列指针不为NULL
	assert(pq->ptail != NULL); // 确保队列不为空,即队尾指针不为NULL

	// 返回队列尾部元素的值
	return pq->ptail->val;
}

这两串获取元素的代码变得十分简单了

判断队列是否为空

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

获取队列元素个数

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

队列的销毁

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;
}

在前面的铺垫之后,我们理解这几个函数就十分简单了

本节内容到此结束!后续我们会更新例题来加强对这个地方的理解!!文章来源地址https://www.toymoban.com/news/detail-835050.html

到了这里,关于数据结构与算法:队列的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法与数据结构(四)--队列

    队列是另一种特殊的表,这种表只在表首(也称为队首)进行删除操作,只在表尾进行插入操作。 队列的修改是按 先进先出 的规则进行的,所以队列又称为先进先出表,First In First Out,简称FIFO表。映射到生活中就是排队的队伍。 如示意图所示,a(1)就是队首元素,a(n)就是队

    2024年02月15日
    浏览(34)
  • 数据结构与算法04:队列

    目录 什么是队列? 循环队列 双端队列 阻塞队列 队列的应用场景 每日一练 在 上一篇文章 中讲述了栈:先进后出就是栈,队列刚好相反, 先进先出的数据结构就是队列 ,还是拿纸箱子来举例:队列可以理解为一个没有底的纸箱子,往箱子里面放书,一本一本叠上去,但是

    2024年02月06日
    浏览(54)
  • 数据结构之栈、队列——算法与数据结构入门笔记(四)

    本文是算法与数据结构的学习笔记第四篇,将持续更新,欢迎小伙伴们阅读学习 。有不懂的或错误的地方,欢迎交流 栈是一种线性数据结构,其 只允许在固定的一端进行插入和删除 元素操作。进行数据插入和删除操作的一端称为栈顶 (Top), 另一端称为栈底 (Bottom)。栈中的

    2024年02月08日
    浏览(27)
  • Python数据结构与算法-数据结构(列表、栈、队列、链表)

    数据结构是指相互之间存在这一种或者多种关系的数据元素的集合和该集合中元素之间的关系组成。 简单来说,数据结构就是设计数据以何种方式组织并存储在计算机中。 比如:列表、集合与字典等都是一种数据结构。 N.Wirth:“程序=数据结构+算法” 数据结构按照其 逻辑结

    2024年02月08日
    浏览(31)
  • 【数据结构与算法】队列的实现

    🌠 作者:@ 阿亮joy. 🎆 专栏:《数据结构与算法要啸着学》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先

    2024年02月07日
    浏览(38)
  • 数据结构与算法-双端队列

    Gitee上开源的数据结构与算法代码库:数据结构与算法Gitee代码库 双端队列、队列、栈对比 定义 特点 队列 一端删除(头)另一端添加(尾) First In First Out 栈 一端删除和添加(顶) Last In First Out 双端队列 两端都可以删除、添加 优先级队列 优先级高者先出队 延时队列 根据

    2024年02月13日
    浏览(28)
  • 数据结构与算法:栈和队列

    栈是一种后入先出(LIFO)的线性逻辑存储结构。只允许在栈顶进行进出操作。 基本操作包括:入栈(push)/出栈(pop)/获取栈顶元素(peek)。 栈的实现主要有两种: 1. 数组实现,即顺序栈 2. 链表实现,即链式栈 无论是以数组还是以链表实现,入栈、出栈的时间复杂度都是

    2024年02月11日
    浏览(37)
  • 【数据结构与算法】设计循环队列

      🧑‍🎓 个人主页:简 料   🏆 所属专栏:C++   🏆 个人社区:越努力越幸运社区   🏆 简       介: 简料简料,简单有料~在校大学生一枚,专注C/C++/GO的干货分享,立志成为您的好帮手 ~ C/C++学习路线 (点击解锁) ❤️ C语言阶段(已结束) ❤️ 数据结构与算法(ing) ❤

    2024年01月17日
    浏览(31)
  • 【数据结构与算法】03 队列(顺序队列--循环队列--优先级队列--链队列)

    队列( queue )是一种常见的数据结构,它遵循先进先出(FIFO)的原则。队列可以理解为一个具有两个端点的线性数据结构,其中一个端点称为\\\"队尾\\\"(rear),用于插入新元素,另一个端点称为\\\"队首\\\"(front),用于移除元素。新元素被插入到队尾,而最早插入的元素总是在队

    2024年02月08日
    浏览(41)
  • 【Java数据结构 -- 队列:队列有关面试oj算法题】

    只允许在一端进行插入数据操作,在另一端进行删除数据操作得特殊线性表,队列是 先进先出 ,入队:进行插入操作得一端称为 队尾(rear) ,出队:进行删除操作的一端称为 队头(front) 。队列Queue是个接口, 底层通过链表实现的 。 boolean offer(E e) – 入队列 E poll() – 出队

    2024年01月25日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包