链式结构实现队列

链式结构实现队列

    • 1.队列
      • 1.1队列的概念及结构
      • 1.2队列的实现
    • 2. 队列的各种函数实现
    • 3. 队列的全部代码实现

1.队列

1.1队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出
FIFO(First In First Out)的原则

入队列:进行插入操作的一端称为队尾

出队列:进行删除操作的一端称为队头

如图所示:
在这里插入图片描述

1.2队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
在这里插入图片描述

2. 队列的各种函数实现

首先,我们先定义一个栈的结构

typedef int QDataType;

//节点的结构
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;

//链表的结构
typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

这里我们定义了两个结构体,这是因为在尾插的时候需要一个尾指针,如果每次尾插的时候都要遍历找尾效率太低,所以,我们可以定义一个尾指针,在头删的时候需要一个头指针,这个size其实可以加上有也可以不加,但是不加上的话求队列长度的时候需要遍历,比较麻烦,多个数据共同管理这个队列,所以,我们可以封装成一个结构体来管理这个队列。

初始化队列

void QueueInit(Queue* pq)
{
	aseert(pq);

	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

销毁队列

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

	QNode* pcur = pq->phead;
	while (pcur)
	{
		QNode* next = pcur->next;

		free(pcur);
		pcur = next;
	}
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

因为,队列中的每个节点的空间都是动态开辟的,所以在用完队列后要及时释放动态开辟的每一个节点。

队尾入队列

void QueuePush(Queue* pq,QDataType x)
{
	assert(pq);

	QNode* newcode = QueueBuyNode(x);
	
	if (pq->phead == NULL)
	{
		assert(pq->ptail == NULL);//防止一个为空一个不为空的情况
		pq->phead = pq->ptail = newcode;
	}
	else
	{
		pq->ptail->next = newcode;
		pq->ptail = pq->ptail->next;
	}

	pq->size++;
}

这里也可以不把申请节点的代码单独写成一个函数,因为这里只有这一个地方会用到申请节点的操作,但是还是建议封装成一个函数,一方面可以提高代码的可读性,另一方面可以在一定程度上避免代码出错。

这里的assert(pq->ptail == NULL);这句代码主要时为了防止自己的代码写错,造成一个为空一个不为空的情况,所以也可以不写,保证写代码的时候细心一点就可以了。

申请一个节点

QNode* QueueBuyNode(QDataType x)
{
	c* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(1);
	}

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

注意:这里是申请一个节点,所以要用定义队列节点的结构体类型 QNode,而不是管理队列的结构题类型

队头出队列

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

	if (pq->phead->next == NULL)
	{
		pq->phead = NULL;
		pq->ptail = NULL;
	}
	else
	{
		QNode* next = pq->phead->next;

		free(pq->phead);
		pq->phead =next;
	}

	pq->size--;
}

这里的队头出数据也就是头删操作,要注意当删除的链表元素只剩一个时,这里的头指针和尾指针同时指向这一个节点,当删除这个节点的时候,头指针和尾指针都会改变,所以,最好单独处理一下。

因为当只有一个节点的时候执行删除操作后,头指针会变成空,所以我们可以在头指针变成空的时候也把尾指针变成空,所以,这个代码也可以这样写。

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

	QNode* next = pq->phead->next;

	free(pq->phead);
	pq->phead = next;
	
	if (pq->phead == NULL)
	{
		pq->ptail = NULL;
	}
	
	pq->size--;
}

获取队列头部元素

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

	return pq->phead->data;
}

想要获取队头元素,只需要返回队头指针指向的元素的值

获取队列尾部元素

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

	return pq->ptail->data;
}

想要获取队尾元素,只需要返回队尾指针指向的元素的值

获取队列中有效元素个数

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

	return pq->size;
}

这里只需要返回控制队列结构里面的size就可以了,如果不把size封装结构体里面就需要遍历链表求队列元素个数,不但麻烦,效率也低。

检测队列是否为空,如果为空返回非零结果,如果非空返回0

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

	return pq->phead == NULL && pq->ptail == NULL;
}

当头指针和尾指针同时指向空的时候,链表一定为空。

3. 队列的全部代码实现

Queue.h

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

typedef int QDataType;

//节点的结构
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;

//链表的结构
typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

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

//销毁队列
void QueueDestroy(Queue* pq);

//队尾入队列
void QueuePush(Queue* pq, QDataType x);

// 队头出队列
void QueuePop(Queue* pq);

//获取队列头部元素
QDataType QueueFront(Queue* pq);

// 获取队列队尾元素
QDataType QueueBack(Queue* pq);

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

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

Queue.c

#include "Queue.h"

// 初始化队列
void QueueInit(Queue* pq)
{
	assert(pq);

	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

//销毁队列
void QueueDestroy(Queue* pq)
{
	assert(pq);

	QNode* pcur = pq->phead;
	while (pcur)
	{
		QNode* next = pcur->next;

		free(pcur);
		pcur = next;
	}
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

QNode* QueueBuyNode(QDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(1);
	}

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

	return newnode;
}

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

	QNode* newcode = QueueBuyNode(x);
	
	if (pq->phead == NULL)
	{
		assert(pq->ptail == NULL);
		pq->phead = pq->ptail = newcode;
	}
	else
	{
		pq->ptail->next = newcode;
		pq->ptail = pq->ptail->next;
	}

	pq->size++;
}

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

	if (pq->phead->next == NULL)
	{
		pq->phead = NULL;
		pq->ptail = NULL;
	}
	else
	{
		QNode* next = pq->phead->next;

		free(pq->phead);
		pq->phead =next;
	}

	pq->size--;
}

//获取队列头部元素
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->phead->data;
}

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

	return pq->ptail->data;
}

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

	return pq->size;
}


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

	return pq->phead == NULL && pq->ptail == NULL;
}

Test.c

#include "Queue.h"

int main()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);

	printf("size : %d\n",QueueSize(&q));

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

	QueueDestroy(&q);

	return 0;
}

因为队列是后进先出的,所以要访问队列里面的元素时,必须要把队列当前元素取出才能访问下一个元素,每可以看到在打印队列里面的内容时,会把队列变成空,那么队列里面的内容就没有了,但时这也是实际当中的需求,所以不会有什么影响。

运行结果如图:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入解析域名短链接生成原理及其在Python/Flask中的实现策略:一篇全面的指南与代码示例

为了构建一个高效且用户友好的域名短链服务&#xff0c;我们可以将项目精简为以下核心功能板块&#xff1a; 1. 用户管理 注册与登录&#xff1a;允许用户创建账户并登录系统。 这部分内容可以参考另一片文章实现&#xff1a; 快速实现用户认证&#xff1a;使用Python和Flask…

Aster实现一台电脑当两台使——副屏使用独立win账号

前言&#xff1a;笔者每年回家&#xff0c;都面临着想要和小伙伴一起玩游戏&#xff0c;但小伙伴没有电脑/只有低配电脑的问题。与此同时&#xff0c;笔者自身的电脑是高配置的电脑&#xff0c;因此笔者想到&#xff0c;能否在自己的电脑上运行游戏&#xff0c;在小伙伴的电脑上…

得物面试:Redis用哈希槽,而不是一致性哈希,为什么?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; Redis为何用哈希槽而不用一致性哈希&#xff1f; 最近…

智能传感器阅读笔记-智能传感器的发展历程、发展趋势及方向

智能传感器的发展历程 第一代智能传感器 第一代智能传感器是数字式传感器&#xff0c;指改造A/D转换模块&#xff0c;并采用数字技术进行信号处理&#xff0c;使输出信号为数字信号&#xff08;或数字编码&#xff09;的传感器&#xff0c;主要由放大器、A/D转换模块、微处理…

解决STM32MP157开发板密码登录问题

开发板密码登录问题是很多人遇到的问题&#xff0c;网上有很多帖子&#xff0c;我也参考过&#xff0c;不太适用&#xff0c;很复杂&#xff0c;甚至会被误导&#xff0c;我差点连ubuntu虚拟机都无法登录了。有的密码匹配&#xff0c;有的取消不了密码。 1、密码配置&#xff…

ABC341 A-F

Toyota Programming Contest 2024#2&#xff08;AtCoder Beginner Contest 341&#xff09; - AtCoder B读不懂题卡了&#xff0c;F读假题卡了&#xff0c;开题开慢了rank了 A - Print 341 题意&#xff1a; 打印一串交替出现的包含N个0&#xff0c;N1个1的01串 代码&…

【案例8】用户中心实现涉及内容和过程

图1 如图1是用盒子模型内容实现的&#xff0c;但是需要了解一些内容。 一.内容知识引入 1.内边距属性&#xff08;padding&#xff09; 为了调整盒子在网页中的显示位置&#xff0c;常常需要为元素设置内边距。内边距也被称为内填充&#xff0c;是指元素内容和边框之间的距离…

Windows程序互斥锁 - 一个程序同时仅允许运行一个实例

Windows程序互斥锁 - 一个程序同时仅允许运行一个实例 前言 鉴于应用逻辑需要&#xff0c;有些Windows应用同时只能运行一个实例。例如&#xff1a;一个电脑只能同时运行一个微信&#xff08;手速快了当我没说&#xff0c;不信你去试试&#xff09;。 怎么实现呢&#xff1f…

Unity 减低GC和优化

文章目录 在Unity中&#xff0c;垃圾收集&#xff08;Garbage Collection, GC&#xff09;是一项重要的内存管理机制&#xff0c;但过度的GC活动可能会导致性能瓶颈。优化Unity项目中的GC涉及减少不必要的对象分配和生命周期管理。以下列举了五个实例来详细说明如何降低GC负担并…

前端工程化面试题 | 11.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

基于ORB-SLAM2与YOLOv8剔除动态特征点

基于ORB-SLAM2与YOLOv8剔除动态特征点 以下方法以https://cvg.cit.tum.de/data/datasets/rgbd-dataset/download#freiburg3_walking_xyz数据集进行实验测试APE 首先在不剔除动态特征点的情况下进行测试&#xff1a; 方法1:segment坐标点集合逐一排查剔除 利用YOLOv8的segm…

Python如何实现定时发送qq消息

因为生活中老是忘记各种事情&#xff0c;刚好又在学python&#xff0c;便突发奇想通过python实现提醒任务的功能&#xff08;尽管TIM有定时功能&#xff09;&#xff0c;也可定时给好友、群、讨论组发送qq消息。其工作流程是&#xff1a;访问数据库提取最近计划——>根据数据…

旅游出门千万别忘带这些!花的不多,享受翻倍!随身wifi看这篇,高性价比高口碑随身wifi推荐

春节长假&#xff0c;大家都去哪儿玩了呢&#xff1f;我反正带着我的小背包&#xff0c;走遍了祖国的大好河山&#xff01; 得益于之前几次长假出行的经验&#xff0c;这次出行体验十分完美。除了详细完备的出行攻略&#xff0c;还有就是一些出行好物&#xff0c;虽然不起眼&am…

第三百四十八回

文章目录 1. 概念介绍2. 使用方法2.1 List2.2 Map2.3 Set 3. 示例代码4. 内容总结 我们在上一章回中介绍了"convert包"相关的内容&#xff0c;本章回中将介绍collection.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章回中介绍的内容是col…

Slider滑动输入条(antd-design组件库)简单使用

1.Slider滑动输入条 滑动型输入器&#xff0c;展示当前值和可选范围。 2.何时使用 当用户需要在数值区间/自定义区间内进行选择时&#xff0c;可为连续或离散值。 组件代码来自&#xff1a; 滑动输入条 Slider - Ant Design 3.本地验证前的准备 参考文章【react项目antd组件-de…

【leetcode994】腐烂的橘子(BFS)

文章目录 一、题目二、思路三、代码 一、题目 二、思路 首先将所有烂橘子入队&#xff0c;然后常规BFS遍历&#xff0c;注意while的截止条件除了队列为空&#xff0c;新鲜橘子数量大于0&#xff08;没新鲜橘子也没必要继续遍历&#xff0c;保证时间计算的正确性&#xff09;&a…

linux内核模块__module_address()函数详解--01

亲爱的粉丝朋友们大家好&#xff0c;为了更好的服务大家&#xff0c;提升分析问题和解决问题的能力&#xff0c;先针对Linux内核里面的API函数进行详细分析&#xff0c;并利用案例进行说明&#xff0c;加强对内核API函数的认识。 第一&#xff1a;函数原型 //函数原型struct m…

【半监督图像分割 2023 】BHPC

【半监督图像分割 2023 】BHPC 论文题目&#xff1a;Semi-supervised medical image segmentation via hard positives oriented contrastive learning 中文题目&#xff1a;通过面向硬阳性的对比学习进行半监督医学图像分割 论文链接&#xff1a; 论文代码&#xff1a;https:/…

C#开源免费的Windows右键菜单管理工具

前言 今天分享一个C#开源、免费、纯粹的Windows右键菜单管理工具&#xff1a;ContextMenuManager。 工具主要功能 程序支持国际化多语言显示。启用或禁用文件、文件夹、新建、发送到、打开方式、自定义文件格式、IE浏览器、WinX等右键菜单项目。对上述场景右键菜单项目进行修…

量子算法入门——3.狄拉克符号与量子态(1)

参考资料&#xff1a; 【【零基础入门量子计算-第04讲】狄拉克符号与量子态】 来自b站up&#xff1a;溴锑锑跃迁 建议关注他的更多高质量文章&#xff1a;CSDN&#xff1a;【溴锑锑跃迁】 1. 狄拉克符号 从生活实例引导到狄拉克符号狄拉克符号 注意这里ket是| >(右矢)&a…