【数据结构】队列及其实现

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

目录

😎前言

认识队列

队列的初始化

队列判空

数据队尾入队

数据队头出队

取队头数据

取队尾数据

队列数据的个数

队列销毁

总结


😎前言

  • 上次我们学习了栈及其实现,当然也少不它的好兄弟队列啦,今天我们开始队列的学习
  • 队列的性质是先进先出,就比如车辆进出隧道一般,它也是一种逻辑结构,依靠数组或者链表实现
  • 在一些算法题我们也会运用到队列的进一步思想——优先队列(由二叉树实现),等到二叉树章节会给大家讲解的。

认识队列

队列和栈一样都是逻辑结构——由数组或者链表加以限制条件而成的,它的逻辑是先入先出,所以入数据是从队尾入,出数据就是从队头出

常见的应用就是银行的取号机,防止有人插队

可以发现如果用数组模拟队列的话,出队的时候就要频繁移动数组内的数据,不是很方便,也要考虑到扩容的问题,所以本篇选取链表的形式来实现队列

队列的初始化

队列本质上就是一个单链表,单链表又是由一个个节点组成,所以自然而然我们要先定义它的结点

typedef struct QNode
{
	struct QNode* next;
	QDataType val;
}QNode;
  • 队列还需要一个指针指向它的队头,一个指针指向队尾,还有一个变量记录存储的数据的个数
  • 所以此处可以选择再用一个结构体对其进行封装,这样操作起来就会简单许多

【数据结构】队列及其实现

 上图就是队列的基本框架了

typedef struct Queue
{
	QNode* front;
	QNode* rear;
	int size;
}Queue;

有了基本结构,那么首先肯定还是对其就行初始化,这里只需要将两个指针都置空,size置0即可

老生常谈的问题,对于函数接口接受的队列来说不能为空,否则就相当于传了一个还没建立好的队列进去,直接assert断言暴打,这是每个函数接口都要用到的,下文就不赘述了

void QueueInit(Queue* q)
{
	assert(q);

	q->front = q->rear = NULL;
	q->size = 0;
}

队列判空

  • 在取数据以及数据出队的时候,往往需要对队列进行判空操作,所以我们先将其封装成一个函数接口
  • 可以提高代码的可读性
  • size及表示存储的数据个数,所以我们返回size==0这个条件判断表达式即可

以下为函数接口实现:

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* q)
{
	assert(q);

	return q->size == 0;
}

数据队尾入队

  • 因为队列是不带头单向不循环链表,队尾入队就是给单链表尾插结点,所以链表学的扎实的同学应该可以反应过来这里需要分类讨论一下
  • 一是队列为空的时候,这个时候插入数据就要改变front和rear指针的指向
  • 二是链表不为空的时候,这个时候只需要改变front指针的指向
  • 先malloc出新结点再进行插入操作
  • size记得++

以下为函数接口实现:

void QueuePush(Queue* q, QDataType data)
{
	assert(q);

	QNode* newnode=(QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail\n");
		return;
	}
	newnode->next = NULL;
	newnode->val = data;

	if (q->rear == NULL)
	{
		assert(q->front==NULL);
		q->front = q->rear = newnode;
	}
	else
	{
		q->rear->next = newnode;
		q->rear = newnode;
	}
	q->size++;
}

数据队头出队

  • 和队尾入队一样,此处仍需要分类讨论
  • 一是普通情况,队头出队就是头删,先记录front的下一个结点next,然后free掉front指针指向的内存空间,然后再将next赋给front
  • 二是只剩一个结点的时候,因为我们值移动front指针,所以操作完rear指针会依然指向被释放的那块空间,就存在野指针的问题
  • 记得size需要--

以下为函数接口实现:

// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));

	//只有一个结点
	if (q->front->next == NULL)
	{
		free(q->front);
		q->front = q->rear = NULL;
	}
	else
	{
		QNode* next = q->front->next;
		free(q->front);
		q->front = next;
	}
	q->size--;
}

取队头数据

  • 如果队列为空,那么就不能返回数据,所以需要assert断言一下,这里也就用到了QueueEmpty函数接口啦
  • 返回的是结点里存储的数据的值,所以函数返回类型是QDataType,不要思维固化地认为是int
  • 返回front->val即可

以下为函数接口实现:

QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));

	return q->front->val;
}

取队尾数据

  • 如果队列为空,那么就不能返回数据,所以需要assert断言一下,这里也就用到了QueueEmpty函数接口啦
  • 返回的是结点里存储的数据的值,所以函数返回类型是QDataType,不要思维固化地认为是int
  • 返回rear->val即可

以下为函数接口实现:

// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));

	return q->rear->val;
}

队列数据的个数

上文提到了size代表存储的数据的个数,这里直接返回size即可

以下为函数接口实现:

// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{
	assert(q);

	return q->size;
}

队列销毁

  • 本质上也就是单链表的销毁,在free掉一个结点前应该先记录其下一个结点
  • 最后的front和rear指针置空,size置0

以下为函数接口实现:

void QueueDestroy(Queue* q)
{
	assert(q);

	QNode* cur = q->front;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->front = q->rear = NULL;
	q->size = 0;
}

总结

👉队列和栈的定义不太相同,用到了两个结构体,这也体现了在数据结构学习的时候需要一些灵活性

🫡只要之前的数据结构都好好实现了,相信队列实现起来也是洒洒水的事情啦

❤️我也会继续输出数据结构相关的博客的,希望大家多多支持!!!文章来源地址https://www.toymoban.com/news/detail-483811.html

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

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

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

相关文章

  • 数据结构及其简单实现

    栈 先进后出 栈顶操作(栈顶进,栈顶出) 含有min函数的栈 辅助栈实现 Math.min方法实现 每日温度 力扣题目 739. 每日温度 队列 先进先出 队首出,队尾入 基于对象 双端队列 队列的最大值 滑动窗口问题 力扣题目 239. 滑动窗口最大值 链表 操作上和数组很像,为什么不用数组?

    2024年01月18日
    浏览(26)
  • 【数据结构】:队列的实现

    队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头 队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如

    2024年02月07日
    浏览(27)
  • 数据结构 | 队列的实现

    队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头 队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如

    2024年02月05日
    浏览(33)
  • 数据结构---队列的实现

    前言 一、什么是队列? 二、 队列接口的实现 1. 队列结构的定义 2. 接口实现 总结 队列是一种特殊的线性表。 特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。 进行插入操作的端称为

    2024年02月02日
    浏览(27)
  • 【数据结构】队列的实现

    队列是一种常用的数据结构,也是一种操作受限制的线性表,特点是只允许在表的头部进行删除操作,在表的尾部进行插入操作,队列具有先进先出FIFO(First In First Out)。 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头 我们实现可以用数组和链表

    2024年02月02日
    浏览(27)
  • 数据结构——队列的实现

    队列 ,又称为伫列(queue),计算机科学中的一种抽象资料类型,是先进先出(FIFO, First-In-First-Out)的线性表。在具体应用中通常用链表或者数组来实现。队列只允许在后端(称为rear)进行插入操作,在前端(称为front)进行删除操作。 这段代码使用 typedef 定义了一个

    2024年02月10日
    浏览(28)
  • 【数据结构—队列的实现】

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、队列 1.1队列的概念及结构 二、队列的实现 2.1头文件的实现—Queue.h 2.2源文件的实现—Queue.c 2.3源文件的测试—test.c 三、测试队列实际数据的展示 3.1正常队列的出入 3.2入队列的同时存

    2024年02月04日
    浏览(32)
  • 数据结构—队列的实现

    前言:上次我们已经学习了数据结构中一个重要的线性表—栈,那么我们这一次就来学习另外一个重要的线性表—队列。 一、 队列的概念 二、 队列的实现: 1.队列的创建 三、 队列的操作 1.初始化队列 2.队尾入队列 3.队头出队列 4.获取队列头部元素 5.获取队列队尾元素 6.获

    2024年02月04日
    浏览(30)
  • 数据结构/队列实现栈

    在学习数据结构的过程当中,我们会学到栈和队列,在本篇文章中,重点讲解的是队列实现栈,在上篇文章中已经简单介绍过栈和队列的使用说明,以及栈实现队列。(2条消息) 数据结构/栈实现队列_Y君的进化史的博客-CSDN博客 关于一个队列的简单使用方式:    关于一个栈的

    2024年02月02日
    浏览(29)
  • 数据结构队列的实现

    本章介绍数据结构队列的内容,我们会从队列的定义以及使用和OJ题来了解队列,话不多说,我们来实现吧 队列 1。队列的概念及结构 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入

    2024年02月11日
    浏览(51)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包