数据结构——队列的实现

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

数据结构——队列的实现

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

typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

这段代码使用 typedef 关键字定义了一个名为 QueueNode 的结构体。QueueNode 结构体包含两个成员:

一个指向另一个 QueueNode 结构体的指针,名为 next,用于表示队列中的下一个节点。
一个名为 data 的变量,其数据类型为 QDataType,用于表示节点中存储的数据。
QNode 被定义为 struct QueueNode* 的别名,也就是说,QNode 是一个指向 QueueNode 结构体的指针。

总的来说,这段代码定义了一个链表节点结构体,可以用来实现队列数据结构,其中每个节点包含一个数据元素和一个指向队列中下一个节点的指针。

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

这段代码使用 typedef 关键字定义了一个名为 Queue 的结构体。Queue 结构体包含三个成员变量:

一个指向 QNode 结构体的指针,名为 head,用于表示队列中的第一个节点。
一个指向 QNode 结构体的指针,名为 tail,用于表示队列中的最后一个节点。
一个整型变量,名为 size,用于表示队列中节点的数量。
这个结构体可以用来实现一个队列数据结构,其中 head 指向队列的开头,tail 指向队列的结尾,size 记录队列中节点的数量。通常情况下,向队列中添加一个节点会使 tail 指针指向新的节点,从队列中移除一个节点会使 head 指针指向下一个节点,并更新 size 的值。

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

这段代码定义了一个名为 QueueInit 的函数,用于初始化一个队列。函数中传入一个指向 Queue 结构体的指针 q,并使用 assert 宏断言 q 不为 NULL。

函数的实现非常简单,将 q 的 head 和 tail 成员都赋值为 NULL,将 size 成员赋值为 0,这样就完成了队列的初始化操作。由于 q 是一个指针,函数中对其进行的操作实际上是对传入的队列进行修改,因此不需要返回值。

// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->data = data;
	newnode->next = NULL;

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

这段代码定义了一个名为 QueuePush 的函数,用于将一个元素插入到队列的尾部。函数中传入一个指向 Queue 结构体的指针 q,以及要插入的数据 data。

函数的实现分为以下几步:

使用 malloc 函数动态分配一个 QNode 结构体大小的内存空间,并将其强制转换为指向 QNode 结构体的指针 newnode。
检查 newnode 是否为空,如果为空则输出错误信息并返回。
将 newnode 的 data 成员赋值为传入的 data,将 newnode 的 next 成员赋值为 NULL,表示 newnode 是队列中的最后一个节点。
检查队列是否为空。如果队列为空,则将队列的 head 和 tail 成员都指向 newnode,表示 newnode 是队列中唯一的节点。
如果队列不为空,则将队列的 tail 节点的 next 指针指向 newnode,表示将 newnode 插入到队列的尾部,并将 tail 指针指向 newnode,表示 newnode 现在是队列中的最后一个节点。
将队列的 size 成员加1,表示队列中节点的数量增加了1。
由于队列是由指针链表实现的,因此在插入节点时需要进行动态内存分配,并将相邻节点的指针进行修改。

// 队头出队列
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->head != NULL);
	QNode* next = q->head->next;
	free(q->head);
	q->head = next;
	if (q->head == NULL)
		q->tail = NULL;
	q->size--;
}

这段代码定义了一个名为 QueuePop 的函数,用于将队列头部的元素弹出队列。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现分为以下几步:

使用 assert 宏检查传入的 q 不为空,以及队列的 head 成员不为 NULL。如果检查失败,则直接返回。
将队列的 head 节点的 next 指针赋值给 next,表示队列头部的下一个节点。
释放队列的 head 节点所占用的内存空间。
将队列的 head 指针指向 next,表示将队列头部的节点弹出队列。
如果队列的 head 成员为 NULL,则将队列的 tail 成员也赋值为 NULL,表示队列已经为空。
将队列的 size 成员减1,表示队列中节点的数量减少了1。
由于队列是由指针链表实现的,因此在弹出节点时需要释放节点的内存空间,并将相邻节点的指针进行修改。

// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->head->data;
}

这段代码定义了一个名为 QueueFront 的函数,用于获取队列头部的元素。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现分为以下几步:

使用 assert 宏检查传入的 q 不为空,以及队列不为空。如果检查失败,则直接返回。
返回队列的 head 节点的 data 成员,即队列头部的元素。
由于队列是由指针链表实现的,因此可以通过访问队列头部节点的 data 成员来获取队列头部的元素。

// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->tail->data;
}

这段代码定义了一个名为 QueueBack 的函数,用于获取队列尾部的元素。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现分为以下几步:

使用 assert 宏检查传入的 q 不为空,以及队列不为空。如果检查失败,则直接返回。
返回队列的 tail 节点的 data 成员,即队列尾部的元素。
由于队列是由指针链表实现的,因此可以通过访问队列尾部节点的 data 成员来获取队列尾部的元素。

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

这段代码定义了一个名为 QueueSize 的函数,用于获取队列中有效元素的数量。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现非常简单,直接返回队列的 size 成员,即队列中有效元素的数量。由于 size 成员是在队列的操作过程中动态更新的,因此可以通过该成员来获取队列中有效元素的数量。

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

这段代码定义了一个名为 QueueEmpty 的函数,用于判断队列是否为空。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现非常简单,通过检查队列的 size 成员是否为0来判断队列是否为空。如果 size 等于0,则队列为空,返回 true(非零结果),否则队列非空,返回 false(0)。

// 销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->head = q->tail = NULL;
	q->size = 0;
}

这段代码定义了一个名为 QueueDestroy 的函数,用于销毁一个队列。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现分为以下几步:

使用 assert 宏检查传入的 q 不为空。
将队列的 head 指针赋值给 cur,表示从队列的头部开始销毁节点。
循环遍历队列中的所有节点,每次将 cur 的 next 指针赋值给 next,然后释放 cur 指向的节点所占用的内存空间。
将 cur 指针指向 next,即将指针移动到下一个节点,继续进行循环直到遍历完所有节点。
将队列的 head 和 tail 成员都赋值为 NULL,将队列的 size 成员赋值为 0,表示队列已经被销毁。
由于队列是由指针链表实现的,因此在销毁队列时需要释放每个节点所占用的内存空间,并将指针移动到下一个节点。文章来源地址https://www.toymoban.com/news/detail-498267.html

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);

//初始化队列
void QueueInit(Queue* q)
{
	assert(q);
	q->head = q->tail = NULL;
	q->size = 0;
}
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->data = data;
	newnode->next = NULL;

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

}
// 队头出队列
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->head != NULL);
	QNode* next = q->head->next;
	free(q->head);
	q->head = next;
	if (q->head == NULL)
		q->tail = NULL;
	q->size--;
}
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->head->data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->tail->data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q)
{
	assert(q);
	return q->size == 0;
}
// 销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->head = q->tail = NULL;
	q->size = 0;
}
int main()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePush(&q, 5);
	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}
	printf("\n");
	
	QueueDestroy(&q);
	return 0;
}
	

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

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

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

相关文章

  • 数据结构:队列Queue详解

    队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。进行插入操作的一端称为 队尾 ,删除操作的一端称 队头 。 入队列 :进行插入操作的一端称为 队尾 。 出队列 :进行删除操作的一端称为 队头 。 在 Java 中, Queue是个接口,底层是通过链表

    2024年02月11日
    浏览(28)
  • [数据结构 -- C语言] 队列(Queue)

    目录 1、队列 1.1 队列的概念及结构 2、队列的实现 2.1 接口 3、接口的实现 3.1 初始化队列 3.2 队尾入队列 分析: 3.3 队头出队列 分析: 3.4 获取队列头部元素 3.5 获取队列尾部元素 3.6 获取队列中有效元素个数 3.7 检测队列是否为空 3.7.1 int 类型判空 3.7.2 bool 类型判空 3.8 销毁队

    2024年02月07日
    浏览(30)
  • Java 数据结构之队列(Queue)详解

    目录 1、在Java中有哪些常见的队列? 2、Queue 接口分析 3、Deque 接口分析 4、PriorityQueue 的实现原理详解 5、使用Java数组实现队列的简单示例 1、在Java中有哪些常见的队列?         在Java中,有一些常见的队列实现。下面是其中一些的列举: //队列也是一种线性的数据结构

    2024年02月15日
    浏览(30)
  • 队列(Queue):先进先出(FIFO)的数据结构

    队列是一种基本的数据结构,用于在计算机科学和编程中管理数据的存储和访问。队列遵循先进先出(First In, First Out,FIFO)原则,即最早入队的元素首先出队。这种数据结构模拟了物理世界中的队列,如排队等待服务的人。 在本篇博客中,我们将详细介绍队列的概念、用途

    2024年02月05日
    浏览(39)
  • 【数据结构】栈和队列超详解!(Stack && Queue)

    栈 :一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则 压栈 : 栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。 出栈 : 栈的删除操

    2024年02月04日
    浏览(32)
  • 数据结构入门到入土——栈(Stack)和队列(Queue)

    目录 一,栈(Stack) 1.1 概念 1.2 栈的使用 1.3 栈的模拟实现 1.4 栈的应用场景 1.5 栈,虚拟机栈,栈帧有什么区别? 二,队列(Queue) 2.1 概念 2.2 队列的使用  2.3 队列模拟实现 2.4 循环队列 三,双端队列 栈 :一种特殊的线性表,其 只允许在固定的一端进行插入和删除元素操

    2024年02月02日
    浏览(44)
  • Java 【数据结构】 栈(Stack)和队列(Queue)【神装】

      登神长阶  第三神装 S tack    第四神装 Queue    目录 🔋一.栈 Stack 💻1.概念 🖥️2.基本操作  🖨️3.相关OJ题   🖱️4.栈、虚拟机栈和栈帧的区别 🪫二.队列 Queue 🖲️1.概念 💽2.基本操作 🔌三.总结与反思         在 Java 中,栈(Stack)是一种后进先出(LIFO)的数

    2024年04月27日
    浏览(26)
  • 【数据结构与算法】C++的STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题

    更多算法例题链接: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题) 什么是迭代器(iterator) 迭代器(iterator)的定义: 迭代器是一种检查容器内元素并遍历元素的数据类型。 迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。 容器

    2024年04月14日
    浏览(37)
  • 数据结构之Queue的实现

    方法名 参数 功能 返回 Size void 返回链表规模(该方法由List T派生而来) empty void 返回链表是否为空(该方法由List T派生而来) front void 返回队首数据域的引用 enqueue T const e 入队 void dequeue void 出队 出队的对象

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

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

    2024年02月07日
    浏览(27)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包