队列详解(C语言实现)

文章目录

  • 写在前面
  • [1 队列的定义](#1 队列的定义)
  • [2 队列的初始化](#2 队列的初始化)
  • [3 数据入队列](#3 数据入队列)
  • [4 数据出队列](#4 数据出队列)
  • [5 获取队头元素](#5 获取队头元素)
  • [6 获取队尾元素](#6 获取队尾元素)
  • [7 获取队列元素个数](#7 获取队列元素个数)
  • [8 判断队列是否为空](#8 判断队列是否为空)
  • [8 队列的销毁](#8 队列的销毁)

写在前面

本片文章详细介绍了另外两种存储逻辑关系为 "一对一" 的数据结构------栈和队列中的队列,并使用C语言实现链队列。

队列C语言实现源码:队列源码

以队列在存储数据时具有特殊的顺序规则:
队列 :使用队列存储数据,遵循 "先进先出 " 的原则,即最先进队列的数据最先出队列。队列也可以分为顺序队列(基于数组实现)和链队列(基于链表实现)。

队列的实现方式分为顺序和链式结构,分别适用于不同的场景。顺序结构在内存中占据一块连续的空间,而链式结构通过节点之间的指针连接。这使得栈和队列在实际应用中更灵活,可以根据具体需求选择不同的实现方式。

1 队列的定义

链式队列的实现其实和之前单链表的实现很类似,只不过队列中数据的进出要遵循 "先进先出" 的原则。
链式队列节点的定义:

c 复制代码
typedef int QDataType;

typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;

队列的定义通常包括两个指针和一个整型,一个指针front指向队列的头,一个指针tail指向队列的尾,还有一个整型size用来记录队列的数据个数。
下面是队列结构的定义:

c 复制代码
typedef struct Queue
{
	QNode* front;//指向队列头部的指针
	QNode* tail;//指向队列尾部的指针
	int size;//记录队列中元素个数
}Queue;

2 队列的初始化

刚开始队列为空,头指针front和尾指针tail指向NULL,此时队列中元素个数为0,因此将size初始化为0。

代码如下:

c 复制代码
void QueueInit(Queue* pq)
{
	assert(pq);//检查参数有效性

	pq->front = pq->tail = NULL;
	pq->size = 0;
}

3 数据入队列

数据入队列分为一下两种情况:

  1. 队列为空时,新建节点,并用要入队列的数据初始化节点,此时front 和 tail都指向新插入的节点,同时将size+1。
  2. 队列不为空时,新建节点,并用要入队列的数据初始化节点,此时tail->next指向新插入的节点,更新tail指向新插入的节点。

数据1 2 3 4 入队列图解:

代码如下:

c 复制代码
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);//检查参数有效性
	//创建新节点
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("QueuePush->malloc");
		exit(-1);
	}
	newnode->next = NULL;
	newnode->val = x;
	//入队列
	//1. 队列为空
	//2. 队列不为空
	if (pq->front == NULL)
	{
		assert(!pq->tail);// 队列为空时,tail front都为空
		pq->front = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}

4 数据出队列

我们知道,队列只能在队尾一端入数据,出数据时只能出队头的数据。因为它要保证有数据元素需要出队时,按照 "先进先出" 的原则。

数据出队的步骤如下:

  1. 在执行数据出队列操作之前,需要检查队列是否为空。如果队列为空(即没有数据),则无法执行出队列操作。
  2. 如果队列不为空,即存在数据,就可以执行出队列操作。
    此时数据出队列又分为两种情况:
    • 队列中只有一个数据:
      此时只需要将该数据所在节点释放,并将 front 和 tail 置为NULL即可。
    • 队列中有两个及以上数据:
      保存头节点下一个节点的地址,释放头节点,更新front,使front指向新的队头元素。

数据1 2 3 4 出队列图解:

代码如下:

c 复制代码
void QueuePop(Queue* pq)
{
	assert(pq);//检查参数有效性
	assert(!QueueEmpty(pq));//检查队列是否为空,为空不能pop

	//出队列
	//1. 队列只有1个元素
	//2.队列有2个以上元素
	if (pq->front->next == NULL)
	{
		free(pq->front);
		pq->front = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->front->next;
		free(pq->front);
		pq->front = next;
	}
	pq->size--;
}

5 获取队头元素

获取队头元素的步骤如下:

  1. 在执行取队头元素操作之前,需要检查队列是否为空。如果队列为空(即没有数据),则无法执行此操作。
  2. 头指针front指向的就是队头元素,如要获取队头元素,因此只需返回front->val即可。

代码如下:

c 复制代码
QDataType QueueFront(Queue* pq)
{
	assert(pq);//检查参数有效性
	assert(!QueueEmpty(pq));//检查队列是否为空,为空不能取队头元素

	return pq->front->val;
}

6 获取队尾元素

获取队尾元素的步骤如下:

  1. 在执行取队尾元素操作之前,需要检查队列是否为空。如果队列为空(即没有数据),则无法执行此操作。
  2. 尾指针tail指向的就是队头元素,如要获取队尾元素,因此只需返回tail->val即可。

代码如下:

c 复制代码
QDataType QueueBack(Queue* pq)
{
	assert(pq);//检查参数有效性
	assert(!QueueEmpty(pq));//检查队列是否为空,为空不能取队尾元素

	return pq->tail->val;
}

7 获取队列元素个数

队列中的size记录的就是队列中元素的个数,如要获取队列元素个数,返回size即可。

代码如下:

c 复制代码
int QueueSize(Queue* pq)
{
	assert(pq);//检查参数有效性

	return pq->size;
}

8 判断队列是否为空

根据队列初始化函数,我们知道,队列为空时,front 和 tail 都指向NULL。

此时size=0,也可以用size来判断,这里作者选择用front 和 tail 来进行判断。

代码如下:

c 复制代码
bool QueueEmpty(Queue* pq)
{
	assert(pq);//检查参数有效性
	return pq->front == NULL && pq->tail == NULL;
}

8 队列的销毁

链队列用来存储数据的节点都是动态申请的,因此队列销毁时,只需要遍历该链队列,依次释放每个节点。最后将 front 和 tail 置为NULL,size 置为0即可。

代码如下:

c 复制代码
void QueueDestroy(Queue* pq)
{
	assert(pq);//检查参数有效性
	QNode* cur = pq->front;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->front = pq->tail = NULL;
	pq->size = 0;
}

至此,本片文章就结束了,若本篇内容对您有所帮助,请三连点赞,关注,收藏支持下。

创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!

如果本篇博客有任何错误,请批评指教,不胜感激 !!!

相关推荐
白晨并不是很能熬夜13 分钟前
【PRC】第 2 篇:Netty 通信层 — NIO 模型 + 自定义协议 + 心跳
java·开发语言·后端·面试·rpc·php·nio
简简单单就是我_hehe27 分钟前
后端链路追踪局部采集和全量采集配置说明
java·开发语言
北京理工大学软件工程30 分钟前
C#111
开发语言·c#
寒秋花开曾相惜1 小时前
(学习笔记)4.2 逻辑设计和硬件控制语言HCL(4.2.1 逻辑门&4.2.2 组合电路和HCL布尔表达式)
linux·网络·数据结构·笔记·学习·fpga开发
叶子野格2 小时前
《C语言学习:指针》12
c语言·开发语言·c++·学习·visual studio
光影少年2 小时前
前端线上屏幕出现卡顿如何排查?
开发语言·前端·javascript·学习·前端框架·node.js
ch3nyuyu2 小时前
静态库和动态库的制作
linux·运维·开发语言
a1117762 小时前
高斯泼溅 (Gaussian Splatting) 的 Three.js 实现
开发语言·javascript·ecmascript
成都渲染101云渲染66662 小时前
云渲染全面支持3dsMax 2027,高效渲染体验升级
开发语言·前端·javascript
一口Linux2 小时前
Linux C编程 | 从0实现telnet获取程序终端控制权
linux·运维·c语言