C语言--队列的创建及使用详解

C语言--队列的创建及使用详解

  • 1. 队列的基本概念
    • 1.1 概念
    • 1.2 结构
    • 1.3 队列结构的选择
  • 2. 队列的创建
    • 2.1 队列基本结构体的搭建
    • 2.2 初始化
    • 2.3 判空
    • 2.4 入队列
    • 2.5 出队列
    • 2.6 返回队头数据
    • 2.7 返回队尾数据
    • 2.8 队列数据个数
  • 3. 队列的使用
    • 3.1 代码使用
    • 3.2 现实场景应用
  • 4. 总结

1. 队列的基本概念

1.1 概念

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

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

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

1.2 结构

基本结构如下图:
C语言--队列的创建及使用详解_第1张图片

最左边是对头,最右边是队尾
当数据传入队列的时候,数据会直接放在队尾的位置,此过程为入队列。
当取数据时,只能从对头的数据依次往后取,此过程为出队列。
队列结构导致了队列中的数据会遵从先进先出FIFO(First In First Out)的原则。

1.3 队列结构的选择

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

本文采用链表结构来实现队列。

队列结构说明
队列主要通过一个头地址 front 和一个尾地址 rear 来控制队列中数据的位置信息。

队列中数据则是由多个链表块数据构成,如下图蓝色方块。

当队列为空时,front 和 rear 均为空,如下图(a).

当有数据进入链表中时,front 和 rear 会分别指向队头和队尾的位置,数据块会通过链表的结构链接起来,结构如下图(b)(c)(d)。

2. 队列的创建

2.1 队列基本结构体的搭建

基于队列结构的特殊性(包含链表数据块和对头头尾指针)以及操作的简便性,创建以下两个结构体对队列进行管理。

typedef int MyQDataType;//宏定义数据类型,便于不同数据的放入

//链表数据块结构的创建
typedef struct QueueNode
{
	MyQDataType data;//存放数据
	struct QueueNode* next;//指向下一个数块地址
}QNode;


//队列结构的创建
typedef struct QueueStack
{
	QNode* phead;//指向队头位置
	QNode* ptail;//指向队尾位置
	int size;//记录数据个数
}Queue;

2.2 初始化

void QueueInit(Queue* pq)
{
	assert(pq);//断言,队列不存在时报错

	pq->phead = NULL;//队头置空
	pq->ptail = NULL;//队尾置空
	pq->size = 0;//数据个数置零
}

2.3 判空

当size 等于0 的时候,队列中数据为空。

bool QueueEmpty(Queue* pq)//布尔判断,为真时返回ture,为假时返回false。
{
	assert(pq);//断言,队列不存在时报错

	return pq->size == 0;//当size 为0时,满足条件,返回ture,否在返回false
	//等价于以下代码
	/*if(pq->size==0)
		return ture;
	else
	retrun false;*/
}

2.4 入队列

入队列要考虑队列是否为空以及头尾指针的位置摆放。

void QueuePush(Queue* pq, MyQDataType x)
{
	assert(pq);//断言,队列不存在时报错
	//创建新的链表数据块,并放入数据
	QNode* newnode = (QNode*)malloc(sizeof(QNode)); 
	if(newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	//队尾指针不为空,即队列中已经存在数据时,数据直接放队尾
	if (pq->ptail != NULL)
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	//队尾指针为空,即队列中无数据时,头指针和尾指针同时指向第一块数据
	else
	{
		pq->ptail = newnode;
		pq->phead = newnode;
	}

	pq->size++;//插入数据,数据个数加一
}

2.5 出队列

出队列要考虑空间的释放以及头尾指针的位置

void QueuePop(Queue* pq)
{
	assert(pq);//断言,队列不存在时报错
	assert(!QueueEmpty(pq));//断言,队列为空时报错
	//单个数据节点
	if (pq->phead->next == NULL)
	{
		free(pq->phead);//直接释放空间
		pq->phead = pq->ptail = NULL;//置空
	}
	//多个数据节点
	else
	{
		Queue* cur = pq->phead->next;//定位下一个节点位置
		free(pq->phead);//释放当前节点空间
		pq->phead = cur;//头指针后移
	}
	pq->size--;//数据个数减一
}

2.6 返回队头数据

需要队头数据的返回类型

MyQDataType QueueFront(Queue* pq)
{
	assert(pq);//断言,队列不存在时报错
	assert(!QueueEmpty(pq));//断言,队列为空时报错

	return pq->phead->data;//返回头指针指向数据块中的数据内容
}

2.7 返回队尾数据

需要队尾数据的返回类型

MyQDataType QueueBack(Queue* pq)
{
	assert(pq);//断言,队列不存在时报错
	assert(!QueueEmpty(pq));//断言,队列为空时报错

	return pq->ptail->data;//返回尾指针指向数据块中的数据内容
}

2.8 队列数据个数

队列数据个数由size 在负责记录,只需要返回size 的大小即可。


int QueueSize(Queue* pq)
{
	assert(pq);//断言,队列不存在时报错
	assert(!QueueEmpty(pq));//断言,队列为空时报错
	
	return pq->size;//返回数据个数
}

3. 队列的使用

3.1 代码使用

void test1()
{
	Queue pq;//创建队列
	QueueInit(&pq);//队列初始化
	//插入数据 1 ~ 6
	QueuePush(&pq, 1);
	QueuePush(&pq, 2);
	QueuePush(&pq, 3);
	QueuePush(&pq, 4);
	QueuePush(&pq, 5);
	QueuePush(&pq, 6);
	//打印插入的数据
	while (!QueueEmpty(&pq))
	{
		printf("%5d\n", QueueFront(&pq));//打印队头数据
		QueuePop(&pq);//使队头数据出队列
	}

	QueueDestroy(&pq);//队列的销毁
}

int main()
{
	test1();
	return;
}

以上代码执行结果:
C语言--队列的创建及使用详解_第2张图片
从结果上来看,实现了先入先出的原则。

3.2 现实场景应用

一、操作系统调度

在操作系统中,队列被广泛应用于进程调度。操作系统需要根据进程的优先级、执行时间等因素来对进程进行调度。这时,可以使用队列来管理等待调度的进程。新到达的进程会排在队列的末尾,而正在执行的进程会从队列的头部取出。这种方式能够保证每个进程都能按照一定的顺序被执行,公平地利用系统资源。

二、网络通信

在网络通信中,队列可以用来处理请求和响应。例如,在Web服务器中,当有多个客户端请求访问网站时,服务器会将这些请求按照先后顺序放入队列中。服务器会从队列的头部取出请求,并进行处理和响应。通过队列的方式,能够有效地处理大量并发请求,保证服务器的稳定性和响应速度。

三、图像处理

在图像处理中,队列可以用来实现图像的滤波操作。滤波操作是图像处理中常用的一种操作,它可以对图像进行平滑、锐化、边缘检测等处理。一种常见的滤波操作是均值滤波,它使用一个滑动窗口在图像上移动,并计算窗口内像素的平均值,然后将平均值赋给滑动窗口的中心像素。这个滑动窗口的移动可以使用队列来实现,新的像素进入队列,旧的像素从队列中移出,从而实现滤波操作。

四、任务调度

在任务调度中,队列可以用来管理待执行的任务。例如,在生产线上,有多个任务需要按照一定的顺序执行,那么可以使用队列来管理这些任务。新的任务进入队列的末尾,而正在执行的任务从队列的头部取出。这样可以确保任务按照一定的顺序执行,提高生产效率。

五、消息传递

在分布式系统中,队列常常被用作消息传递的中间件。当多个系统之间需要传递消息时,可以使用队列来实现。发送者将消息放入队列中,接收者从队列中取出消息进行处理。队列可以保证消息的顺序和可靠性,确保消息的正确传递。

六、打印队列

在打印机管理中,队列可以用来管理打印任务。当多个用户同时提交打印任务时,这些任务可以按照先后顺序排队进入打印队列。打印机从队列中取出任务进行打印,直到队列为空。通过队列的方式,能够有效管理打印任务,保证打印机的高效利用。

4. 总结

队列结构是一种变相的链表结构,相比于单独的链表,它多了一个包含队头指针和队尾指针的结构体,但其实质上,仍旧属于链表结构。只要掌握了链表结构,队列结构的实现会变得比较简单。

你可能感兴趣的:(c语言,开发语言,算法,学习,链表)