数据结构:线性表之-队列

news2024/11/25 2:30:51

目录

什么是队列?

详解:

功能介绍

代码实现

定义队列基本结构

1,初始化

2, 销毁

3,尾入数据

4,头出数据

5,取队头的数据

6,取队尾的数据

7,判断是否为空

8,计算队列中的元素

成品

Queue.h

Queue.c

test.c


队列的讲解将建立在有双向链表的基础之上进行讲解
当然队列只是链表的一种分支
单项链表详解:# 数据结构:线性表之-单向链表(无头)
双向链表详解:# 数据结构:线性表之-循环双向链表(万字详解)

什么是队列?


队列是一种常见的数据结构,用于存储和管理数据的集合。它遵循先进先出(FIFO)的原则,即最先进入队列的元素最先被删除。类比一下,你可以把队列视为排队等待服务的人群,新来的人排在队列末尾,而需要服务的人从队列头部被依次处理。

队列通常有两种基本操作:

  1. 入队(enqueue):将元素添加到队列的末尾。
  2. 出队(dequeue):从队列的头部删除一个元素,并返回被删除的元素。

除了入队和出队操作,队列还可以支持其他操作,如获取队列的大小(元素个数)、判断队列是否为空等。队列在计算机科学中有广泛的应用,例如任务调度、缓冲区管理、计算机网络等领域。
当队列已满时,新的元素无法入队,我们称之为队列满(Queue Full)。
当队列为空时,没有元素可以出队,我们称之为队列空(Queue Empty)。

队列的实现方式有多种,最常见的是使用数组或链表来存储元素。在数组实现中,我们使用一个固定大小的数组来存储元素,并使用两个指针(front和rear)分别指向队列的头部和尾部。入队操作时,将元素添加到rear指针所指位置,并将rear指针向后移动一位;出队操作时,将front指针所指位置的元素删除,并将front指针向后移动一位。

队列的应用非常广泛。举例来说,在计算机的操作系统中,进程调度算法通常使用队列来管理待执行的进程。在网络数据传输中,数据包也会按照先后顺序排队等待传输。此外,实现广度优先搜索算法、缓冲区处理等也需要使用队列。队列数据结构的特性使得它在这些场景下非常实用,能够提高程序的效率和性能。

详解:

功能介绍

//初始化
void QueueInit(Queue* pq);

//销毁
void QueueDestory(Queue* pq);

//尾入数据
void QueuePush(Queue* pq, QDataType x);

//头出数据
void QueuePop(Queue* pq);

//取队头的数据
QDataType QueueFront(Queue* pq);

//取队尾的数据
QDataType QueueBack(Queue* pq);

//判断是否为空
bool QueueEmpty(Queue* pq);

//计算队列中的元素
int QueueSize(Queue* pq);

代码实现

定义队列基本结构

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

typedef struct Queue
{
	//定义两个指针,tail方便尾插
	//方便对头出数据,尾入数据
	QNode* head;
	QNode* tail;
}Queue;

1,初始化

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
}

2, 销毁

void QueueDestory(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
}

这段代码实现了队列的销毁操作。
它接受一个指向队列的指针 pq,并通过遍历队列中的每个节点来逐个释放它们的内存。
首先,它在 assert 语句中检查指针 pq 是否为空,以确保操作的安全性。
然后,它将队列的头指针 pq->head 赋值给局部变量 cur,作为遍历的起始点。
接下来使用一个循环来遍历队列的每个节点。在每次循环中,它首先将当前节点 cur 的下一个节点保存在指针变量 next 中,以便能够继续遍历队列。
然后,它使用 free 函数释放当前节点 cur 的内存。
最后,它将 cur 更新为 next,以便在下一次循环中继续遍历。在循环结束后,它将队列的头指针 pq->head 和尾指针 pq->tail 都设为 NULL,表示队列已经为空了。
这段代码确保了在销毁队列后,所有节点的内存都得到了正确的释放,以避免内存泄漏。

3,尾入数据

void QueueDestory(Queue* pq)
{
	assert(pq);
	//QNode* cur = pq->head;`:创建一个指针 `cur`,
    //并将其初始化为指向队列的头节点。这将是遍历队列的起点
	QNode* cur = pq->head;
	while (cur)
	{
		//创建一个指针 `next`,将其指向当前节点 `cur` 的下一个节点。
		//这是为了保留对下一个节点的引用,以便在释放当前节点后继续访问。
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	//在循环结束后,将队列的头指针 `pq->head` 
    //和尾指针 `pq->tail` 都设置为 NULL,表示队列为空。
	pq->head = pq->tail = NULL;
}

4,头出数据

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	/*1,只有一个头节点
	2,多个节点*/
	//判断队列是否只有一个节点。如果队列只有一个节点,即头节点,进入 `if` 语句。
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		//创建一个指针 `next`,将其指向头节点的下一个节点。
		QNode* next = pq->head->next;
		free(pq->head);
		//将指针 `pq->head` 更新为 `next`,即将头指针指向下一个节点。
		pq->head = next;
	}
}

5,取队头的数据

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

	return pq->head->data;
}

6,取队尾的数据

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->tail->data;
}

7,判断是否为空

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->head == NULL;
}

8,计算队列中的元素

int QueueSize(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	int size = 0;
	while (cur)
	{
		++size;
		cur = cur->next;
	}
	return size;
}

此处是单独创建一个函数进行计算队列中的元素个数
另一种方法是在定义队列基本结构的结构体中定义一个int size
每次尾增时++size
每次头删时–size

成品

Queue.h

#pragma once

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>

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

typedef struct Queue
{
	//定义两个指针,tail方便尾插
	//方便对头出数据,尾入数据
	QNode* head;
	QNode* tail;
}Queue;

//初始化
void QueueInit(Queue* pq);

//销毁
void QueueDestory(Queue* pq);

//尾入数据
void QueuePush(Queue* pq, QDataType x);

//头出数据
void QueuePop(Queue* pq);

//取队头的数据
QDataType QueueFront(Queue* pq);

//取队尾的数据
QDataType QueueBack(Queue* pq);

//判断是否为空
bool QueueEmpty(Queue* pq);

//计算队列中的元素
int QueueSize(Queue* pq);

Queue.c

#include "Queue.h"

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

//销毁
void QueueDestory(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
}

//尾入数据
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}

	newnode->data = x;
	newnode->next = NULL;

	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;

	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

//头出数据
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	//1,只有一个头节点
	//2,多个节点
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

//取队头的数据
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->head->data;
}

//取队尾的数据
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->tail->data;
}

//判断是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->head == NULL;
}

//计算队列中的元素
int QueueSize(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	int size = 0;
	while (cur)
	{
		++size;
		cur = cur->next;
	}
	return size;
}

test.c

test.c只是用于测试代码,菜单的写法本文将不进行讲解。
但test.c中含有对查找and销毁and存储链元素个数的使用方法进行了示例可以当参考。

#include "Queue.h"

void test()
{
	Queue q;
	QueueInit(&q);

	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);

	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}
	printf("\n");

	QueueDestory(&q);
}

int main()
{
	test();

	return 0;
}

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

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

相关文章

Oracle使用遇到的问题

一、Navicat 连接Orcle提示 Oracle library is not loaded 1.前往官网下载客户端 http://www.oracle.com/technetwork/database/database-technologies/instant-client/downloads/index.html 2.选择与系统匹配的“Instant Client”和sqlpus。

App的专项测试

文章目录 App的专项测试都从哪个方面测试安装和卸载版本升级消息推送弱网测试兼容性测试交互性测试 App的专项测试都从哪个方面测试 在APP测试过程中&#xff0c;除了功能测试外&#xff0c;还需要进行一些专项测试来发现更为深层的问题&#xff0c;这些问题主要是针对某个特殊…

时空智友企业流程化管控系统文件存在任意文件上传漏洞 附POC

、 文章目录 时空智友企业流程化管控系统文件存在任意文件上传漏洞 附POC1. 时空智友企业流程化管控系统文件简介2.漏洞描述3.影响版本4.fofa查询语句5.漏洞复现6.POC&EXP7.整改意见8.往期回顾 时空智友企业流程化管控系统文件存在任意文件上传漏洞 附POC 免责声明&#…

【Redis】深入探索 Redis 的哨兵(Sentinel)机制原理,基于 Docker 模拟搭建 Redis 主从结构和哨兵分布式架构

文章目录 一、对 Redis Sentinel 的认识1.1 什么是 Redis Sentinel1.2 为什么要使用 Redis Sentinel1.2.1 主从复制问题1.2.2 人工恢复主节点故障 二、Redis Sentinel 原理剖析2.1 Redis Sentinel 架构2.2 Raft 算法和领袖节点2.3 哨兵节点2.4 故障检测2.5 故障切换2.6 监控和通…

Android调用相册并展示选中的图片

调用相册 //定义请求码int PICK_PHOTO_REQUEST 1234;int RESULT_CANCELED 0;//定义取消码//触发监听后调用相册findViewById(R.id.image_gallery).setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View view) {//创建一个意图并开启startActivi…

Visual Studio 2017 安装

C自学精简实践教程 目录(必读) 这篇文章会保证你第一次安装VS2017就成功运行Hello World! 下载Visual Studio Installer Gitee 下载 VS2017/vs2017_Community.exe CalmReason/VisualStudio - 码云 - 开源中国 (gitee.com) 百度云下载 链接&#xff1a;https://pan.baidu…

ArangoDB关键知识点汇总大全(不定时更新)

二、ArangoDB数据模型与索引 2.1 数据模型 ArangoDB的数据模型分为数据库(databse)、集合(collection)、文档(document)&#xff0c;分别与RDBMS中的数据库、表、行对应。 数据类型包括&#xff1a;string、boolean、number、array、document/object Collection&#xff1a…

【详细图文】Windows下安装RustRover和配置Rust环境

前言 Rust已经火了挺长时间了&#xff0c;连微软的Windows内核都用它来重新改写&#xff0c;可想而知其厉害之处。之前有看过Rust的教程&#xff0c;但一直没有去尝试。今天看到JetBrains出了Rust 专用的IDE&#xff1a;RustRover。作为JetBrains的粉丝&#xff0c;决定进行一…

【强化学习】02—— 探索与利用

文章目录 1. 探索与利用2. 探索策略3. 多臂老虎机3.1. 形式化描述3.2. 估计期望奖励3.3. 懊悔regret函数 4. 贪心策略和 ϵ − g r e e d y \epsilon-greedy ϵ−greedy策略5. 积极初始化6. 显示地考虑动作的价值分布7. UCB上置信界算法8. 汤普森采样算法总结参考 1. 探索与利用…

Hive 的权限管理

目录 ​编辑 一、Hive权限简介 1.1 hive中的用户与组 1.1.1 用户 1.1.2 组 1.1.3 角色 1.2 使用场景 1.2.1 hive cli 1.2.2 hiveserver2 1.2.3 hcatalog api 1.3 权限模型 1.3.1 Storage Based Authorization in the Metastore Server 1.3.2 SQL Standards Based …

【Vue.js】vue-cli搭建SPA项目并实现路由与嵌套路由---详细讲解

一&#xff0c;何为SPA SPA&#xff08;Single Page Application&#xff09;是一种 Web 应用程序的开发模式&#xff0c;它通过使用 AJAX 技术从服务器异步加载数据&#xff0c;动态地更新页面内容&#xff0c;实现在同一个页面内切换不同的视图&#xff0c;而无需整页刷新 1.…

部署Kafka

kafka&#xff1a;kafka_2.13-3.5.1 NOTE: Your local environment must have Java 8 installed. Apache Kafka can be started using ZooKeeper or KRaft. To get started with either configuration follow one the sections below but not both. 1 Windows单机 1.1 Kafka w…

wx.canvasToTempFilePath导出的图片不清晰

使用wx.canvasToTempFilePath接口&#xff0c;导出的canvas图片在手机上看不清晰 解决办法&#xff1a;本质上就是生成一个更大的图片&#xff0c;因为手机的屏幕设备的像素比现在一般都是超过2的。实际上我们只需要在使用wx.canvasToTempFilePath的时候&#xff0c;设置参数d…

LabVIEW在运行时调整表控件列宽

LabVIEW在运行时调整表控件列宽 如何在LabIEW中运行时调整表控件的列宽大小&#xff1f; 在VI运行时&#xff0c;有两种不同的方法可以更改表中列的宽度。首先&#xff0c;可以使用鼠标手动更改它们;其次&#xff0c;可以从框图中以编程方式更改它们。 手动更改列宽 只有在…

Unity中UI组件对Shader调色

文章目录 前言一、原理在Shader中直接暴露的Color属性&#xff0c;不会与UI的Image组件中的Color形成属性绑定。因为UI的Image组件中更改的颜色是顶点颜色&#xff0c;如果需要在修改组件中的颜色时&#xff0c;使Shader中的颜色也同时改变。那么就需要在应用程序阶段传入到顶点…

Docker容器启动失败:找不到映像

Docker容器启动失败&#xff1a;找不到映像 Docker容器启动失败&#xff1a;找不到映像摘要 &#x1f615;引言 &#x1f62e;正文 &#x1f913;为什么会找不到映像&#xff1f; &#x1f615;1. 映像不存在2. 映像标签错误3. 映像不兼容 如何预防和解决问题&#xff1f; &…

国家开放大学 考试试题训练

经济数学基础 参考 试题 导数基本公式&#xff1a; 积分基本公式&#xff1a; c0 ∫0dxc xaaxa-1 ∫xadxxa1a1c&#xff08;a≠-1&#xff09; axaxlna(a>0且a≠1) …

大转盘抽奖活动制作流程,让你轻松打造火爆营销活动

抽奖活动一直是商家吸引顾客、推广产品的利器之一。而如何让抽奖活动更加顺利、高效地进行呢&#xff1f;今天我们就要介绍的就是乔拓云平台&#xff0c;通过它&#xff0c;商家可以轻松地制作、发布抽奖活动&#xff0c;让您的营销更加便捷、迅速&#xff01;以下是具体操作步…

总结 HTTP 协议的基本格式和 fiddler 的用法

HTTP基本格式 HTTP协议也是日常开发中非常常用的的一种协议&#xff0c;在众多协议栈里HTTP可能是实际开发中用的最多的。 注意 这里说的HTTP是指HTTP1以及HTTP2&#xff0c;他们都是基于TCP协议的&#xff0c;注意&#xff1a;如今最新版的HTTP3是基于UDP的。 但如今在互联网…

基于矩阵分解算法的智能Steam游戏AI推荐系统——深度学习算法应用(含python、ipynb工程源码)+数据集(三)

目录 前言总体设计系统整体结构图系统流程图 运行环境模块实现1. 数据预处理2. 模型构建1&#xff09;定义模型结构2&#xff09;优化损失函数 3. 模型训练及保存1&#xff09;模型训练2&#xff09;模型保存 4. 模型应用1&#xff09;制作页面2&#xff09;模型导入及调用3&am…