数据结构初级<队列>

本文已收录至《数据结构(C/C++语言)》专栏,欢迎大家 👍点赞 + 👆收藏 + 🫰关注 


目录

前言

正文

队列的数据结构

队列的操作函数

队列的实现

初始化队列

入队函数

出队函数

查询队头数据函数

查询队尾数据函数

查询队列元素个数函数

检查队空函数

链队列销毁函数

总结


前言

大家看到文章的标题,可能会对队列有许多的联想,我们可以想象我们平时上学时大课间站队做操时的情景,先来的人站在最前面,后来的人依次在队尾向后站,数据结构中队列的性质也与此相似,这一节我们就来学习数据结构中的队列!


正文

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头。

 

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

总而言之,队列的操作在队头和队尾,头出尾进,因此具有先进先出的性质。


队列的数据结构


构建动态链式队列,首先每个节点需要单链表的数据结构,其次我们需要一个头尾指针记录头节点地址和尾节点地址,方便入队和出队,这里的入队和出队类似于头删和尾插,其次我们需要一个整型变量记录队列元素个数。

typedef int QDataType;

// 链式结构:表示队列 
typedef struct QListNode//单链表结构
{
	struct QListNode* _next;//后继指针
	QDataType _data;//数据域
}QNode;

// 队列的结构 
typedef struct Queue队列结构
{
	QNode* _front;//头指针
	QNode* _rear;//尾指针
	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);

// 检测队列是否为空,如果为空返回1,如果非空返回0
int QueueEmpty(Queue* q);

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

队列的实现


初始化队列

对于队列的初始化,我们需要置空头指针和尾指针,防止野指针的访问,其次需要置0记录队列元素个数的变量size。

// 初始化队列 
void QueueInit(Queue* q)
{
	assert(q);//检查空指针
	q->_front = q->_rear = NULL;//头尾指针置空
	q->size = 0;//元素个数置空
}

入队函数

队列的入队在队尾,与单链表的尾插相似,我们只需要申请一个新的节点,然后将新节点的_next指向尾头节点,而原尾节点的地址是_rear指向的地址,我们指向将新节点链接在当前尾节点的后面,然后修改_rear地址的指向,使_rear指向新(尾)节点即可!

但是这里我们需要判断是否是首次入队,如果是首次入队需要将首节点的地址赋给头指针!

入队动图演示
// 队尾入队列 
void QueuePush(Queue* q, QDataType x)
{
	assert(q);//检查空指针
	QNode* newnode = (QNode*)malloc(sizeof(QNode));//申请一个新节点
	if (!newnode)//判断是否申请成功
	{
		perror("malloc fail!\n");
		exit(-1);
	}

	newnode->_data = x;//赋值新节点
	newnode->_next = NULL;//先置空新节点的指针

	if (!q->_rear)//判断是否为首次插入
	{
		
		q->_front = q->_rear = newnode;//如果是则直接插入且将节点地址赋给头尾指针
	}
	else
	{
        //如果不是则让当前尾节点指向新节点,尾指针指向新(尾)节点
		q->_rear->_next = newnode;//尾指针节点的next指向新节点
		q->_rear = newnode;//尾指针指向新节点
	}
	++(q->size);//队列元素个数加1
}

出队函数

队列的出队在队头,与单链表的头删相似,在删除前需要判断队列是否为空,定义一个变量保存即将删除的节点,然后让头指针_front指向原头节点的下一个节点,free释放原头节点的内存空间元素个数_size减一即可。

这里我们要注意的是,我们需要判断删除的是否是队列中最后一个节点,如果是则需要在删除节点后置空头指针_front和尾指针_rear,防止野指针的访问!

出队动图演示
// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q);//判断指针是否为空
	if (!QueueEmpty(q))//判断队列是否为空
	{
		QNode* freenode = q->_front;//存储当前的头节点方便释放
		if ((q->_front) != (q->_rear))//判断是否为最后一个节点
		{
			q->_front = q->_front->_next;//头指针指向头节点的下一个
			free(freenode);//释放原头节点地址空间
		}
		else//释放最后一个节点
		{
			q->_front = q->_rear = NULL;//置空头尾指针防止野指针访问
			free(freenode);//释放最后一个节点的地址空间
		}
		--(q->size);//队列元素个数减一
	}
}

查询队头数据函数

取队头函数是取头节点的数据,如果头节点存在则函数返回头节点的_data数据,如果不存在则返回-1(或其他提示性反馈)。

// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
	assert(q);//检查空指针
	if (!QueueEmpty(q))//判断队列是否为空
	{
		return q->_front->_data;//返回头节点的data数据
	}
	return -1;//为空返回-1(或其他提示性反馈)
}

查询队尾数据函数

取队尾数据与取队头一样,尾节点存在则返回尾节点的_data数据,不存在则返回-1(或其他提示性反馈)。

// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(q);//判断是否为空指针
	if (!QueueEmpty(q))//判断队列是否为空
	{
		return q->_rear->_data;//返回队尾节点的data数据
	}
	return -1;//为空返回-1(或其他提示性反馈)
}

查询队列元素个数函数

查询队列元素个数,我们只需要返回记录节点个数的结构体成员size即可。

// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{
	assert(q);//检查空指针
	return q->size;//返回元素个数
}

检查队空函数

检查队列是否为空我们只需要判断头指针_front和尾指针_rear为NULL且size等于0即可!如果为空则返回1,不为空返回0。

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q)
{
	assert(q);//判断空指针
    //如果头尾指针都为空且size=0则队列为空,返回1
	return ( q ->_front == NULL && q ->_rear == NULL && q->size == 0);
}

链队列销毁函数

队列的销毁从队头开始,定义一个变量cur遍历使用free释放每个节点的内存空间,指导cur遍历到队尾节点的_next为NULL,迭代停止,销毁结束!在执行销毁时如果队列已经为空则不需要销毁!

销毁队列动图演示

总结

这次我们介绍了特殊线性表之一队列,队列是一种特殊的线性表,队列的操作只能在队头和队尾,队列和栈一样常用于辅助一些其他的数据结构实现一些复杂的功能,看完本节相信大家对队列的操作已经有了一定的了解。

本次队列的基础知识介绍就到这里啦,希望能够尽可能帮助到大家。

如果文章中有瑕疵,还请各位大佬细心点评和留言,我将立即修补错误,谢谢!

博客中的所有代码合集:链队列

🌟其他文章阅读推荐🌟

数据结构初级<带头双向循环链表>_CSDN博客

数据结构初级<线性表之链表>_CSDN博客

数据结构初级<线性表之顺序表>_CSDN博客

🌹欢迎读者多多浏览多多支持!🌹

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Java初级数据结构与算法是指在Java编程语言中使用的基本数据结构和算法。在Java中,我们可以使用各种数据结构来存储和操作数据。常见的数据结构包括数组、链表、栈、队列和树等。这些数据结构可以用来解决各种实际问题,如搜索、排序、查找和插入等。 在Java中,我们可以使用ArrayList类来实现动态数组,LinkedList类来实现链表,Stack类来实现栈,Queue接口来实现队列,以及TreeSet和HashMap等类来实现树和哈希表等数据结构。这些数据结构提供了各种方法来操作和管理数据,如添加元素、删除元素、查找元素和遍历元素等。 此外,算法是解决问题的步骤和方法。在Java中,我们可以使用各种算法来处理数据结构中的数据。常见的算法包括线性搜索、二分搜索、冒泡排序、快速排序和图遍历等。这些算法可以帮助我们高效地处理和操作数据。 总结来说,Java初级数据结构与算法是指在Java编程语言中使用的基本数据结构和算法,包括数组、链表、栈、队列、树和哈希表等数据结构,以及搜索、排序、查找和遍历等算法。通过学习和掌握这些数据结构和算法,我们可以更好地解决实际问题并提高程序的效率。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [【Java】数据结构与算法入门](https://blog.csdn.net/LongLiveThePRC/article/details/124573277)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [1.0 JAVA数据结构与算法](https://blog.csdn.net/xiexieya233/article/details/124082025)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [java基础语法:数据结构和算法](https://blog.csdn.net/qq_50395011/article/details/109739043)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ARMCSKGT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值