数据结构--队列(图文)

队列是一种特殊的线性表,其核心特点是先进先出。

概念及特点:

概念

队列是一种只允许在一端进行插入数据操作,在另一端进行删除数据操作的线性表。进行插入操作的一端被称为队尾(Tail 或 Rear),进行删除操作的一端被称为队头(Head 或 Front)。在日常生活中,我们可以将队列比作排队等候的场景,排在前面的人会先得到服务,新来的人则排在队尾等待。

特点:

  1. 先进先出(FIFO):队列的基本操作是入队和出队。入队操作是在队尾插入一个元素,而出队操作是从队头删除一个元素。这意味着最先进入队列的元素将最先被移除。

  2. 操作受限:与普通的线性表不同,队列的操作是受限制的。只能在队尾添加元素,只能在队头删除元素。

  3. 两种实现方式:队列可以通过数组或链表来实现。使用数组实现时,可能会遇到数组空间受限的问题,但可以通过循环队列的方式解决。使用链表实现时,可以动态地分配内存,但可能会有额外的内存开销。

  4. 动态变化:队列是一种动态的数据结构,其大小可以根据需要动态变化。在入队和出队操作时,队列的大小会相应地增加或减少。

  5. 应用广泛:队列在计算机科学中有广泛的应用,如广度优先搜索、任务调度、缓冲处理、线程同步等。

队列的操作

  • 初始化:创建一个空队列。

  • 入队:将一个元素添加到队列的末尾,即队尾。

  • 出队:从队列的开头,即队首,移除元素并返回该元素的值。

  • 返回队首元素:返回队列中的第一个元素的值,但不从队列中删除该元素。

  • 返回队尾元素):返回队列中的末尾元素的值,但不从队列中删除该元素。

  • 获取队列元素个数:返回队列中的末尾元素的值,但不从队列中删除该元素。

  • 判断队列是否为空: 检查队列中是否没有任何元素。

  • 销毁队列:释放队列所占用的存储空间,使得队列不再存在。

队列的应用

队列的应用场景包括但不限于:

  • 打印机任务队列:打印机按照任务进入队列的顺序进行打印,确保了公平性和先到先服务的原则。

  • 网络请求处理:服务器使用队列来管理并响应客户端的请求,保证了请求按照到达顺序被处理。

  • 生产线作业:在生产线上,队列模型用于管理产品的生产流程,确保每个产品都能按照顺序经过各个加工阶段。

  • 消息队列:在消息传递系统中,消息被放入队列,然后由消费者按照顺序处理,支持异步消息处理和负载均衡。

  • 任务队列:在Web服务器和后台处理系统中,任务队列用于管理和调度异步任务,如发送电子邮件、处理图像等。

  • 优先级队列:在需要优先处理的场景中,如紧急任务或高价值任务,使用优先级队列可以确保这些任务能够优先被执行。

队列的实现

这里我们使用链表来实现队列。

首先创建三个文件:

  • Queue.h ------ 用于声明函数的头文件。
  • Queue.c ------ 队列主要函数的实现。
  • test.c------测试队列。

队列节点的定义

这里和单链表结构一致。

c 复制代码
// 链式结构:表示队列 
typedef int QDataType;
typedef struct QListNode
{
	struct QListNode* next;
	QDataType data;
}QNode;

队列指针的定义

将队列的首尾指针封装成一个结构体,可以方便函数调用,统一接口。再使用一个整型size记录元素个数,利于其他函数功能实现。

c 复制代码
// 队列的结构 
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

初始化

c 复制代码
// 初始化队列 
void QueueInit(Queue* q)
{
	assert(q);//队列必须存在
	q->head = q->tail = NULL;
	q->size = 0;
}

销毁队列

创建指针循环遍历链表,每次记录下指针的下一个节点,释放指针指向的节点,指针指向下一个节点

c 复制代码
// 销毁队列 
void QueueDestroy(Queue* q)
{
	assert(q);
	while (q->head)//释放所有节点
	{
		QNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}
	q->head = q->tail = NULL;
	q->size = 0;
}

入队列(队尾插入)

  • 情况一:队列为空直接申请新节点给头节点和尾节点;
  • 情况二:队列不为空,将新节点接入尾节点后即可。
c 复制代码
// 队尾入队列 
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)//判定是否申请成功
	{
		perror("newnode error\n");
		exit(1);
	}
	newnode->data = data;
	newnode->next = NULL;
 
	if (q->head == NULL)//对空队列入队的处理
	{
		q->head = q->tail = newnode;
	}
	else               //对非空队列入队的处理
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;
}

出队列(队头删除)

  • 情况一:队列只有一个节点,直接释放即可;
  • 情况二:队列有多个节点,将头节点的下一个节点保存后释放头节点,在让头节点指向保存的节点。
c 复制代码
// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->head);//队列不能为空
	if (q->head == q->tail)//对只有一个元素的队列的出队处理
	{
		free(q->head);
		q->head = q->tail = NULL;
	}
	else          //对存在多个元素的队列的出队处理
	{
		QNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}
	q->size--;
}

获取队头元素

c 复制代码
// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->head);//队列不能为空
	return q->head->data;
}

获取队尾元素

c 复制代码
// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->head);
	return q->tail->data;
}

获取队列元素个数

c 复制代码
// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}

队列判空

c 复制代码
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->size == 0;
}

队列源码

Queue.h

c 复制代码
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
 
// 链式结构:表示队列 
typedef int QDataType;
typedef struct QListNode
{
	struct QListNode* next;
	QDataType data;
}QNode;
 
// 队列的结构 
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	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);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);

Queue.c

c 复制代码
#include"Queue.h"
 
// 初始化队列 
void QueueInit(Queue* q)
{
	assert(q);//队列必须存在
	q->head = q->tail = NULL;
	q->size = 0;
}
 
// 队尾入队列 
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)//判定是否申请成功
	{
		perror("newnode error\n");
		exit(1);
	}
	newnode->data = data;
	newnode->next = NULL;
 
	if (q->head == NULL)//对空队列入队的处理
	{
		q->head = q->tail = newnode;
	}
	else               //对非空队列入队的处理
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;
}
 
// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->head);//队列不能为空
	if (q->head == q->tail)//对只有一个元素的队列的出队处理
	{
		free(q->head);
		q->head = q->tail = NULL;
	}
	else          //对存在多个元素的队列的出队处理
	{
		QNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}
	q->size--;
}
 
// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->head);//队列不能为空
	return q->head->data;
}
 
// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->head);
	return q->tail->data;
}
 
// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}
 
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->size == 0;
}
 
// 销毁队列 
void QueueDestroy(Queue* q)
{
	assert(q);
	while (q->head)//释放所有节点
	{
		QNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}
	q->head = q->tail = NULL;
	q->size = 0;
}
相关推荐
XiaoCCCcCCccCcccC1 小时前
C语言实现双向链表
c语言·开发语言·链表
夏天的阳光吖2 小时前
每日一题---OJ题:分隔链表
数据结构·链表
Slow2 小时前
Linux静态库的制作
linux·c语言
托马斯-木2 小时前
malloc、calloc、realloc的区别
c语言·内存
gopher95113 小时前
Linux多进程和多线程(五)进程间通信-消息队列
linux·服务器·c语言·开发语言·进程
CylMK3 小时前
NOI大纲——普及组——二叉搜索树
开发语言·数据结构·c++·算法
to-and-fro3 小时前
Nginx中封装的数据结构
运维·数据结构·nginx
3 小时前
数据结构:期末考 第六次测试(总复习)
c语言·数据结构
hummhumm3 小时前
数据结构第06节:栈
java·开发语言·数据结构·spring boot·spring·java-ee·intellij-idea
hummhumm5 小时前
数据结构中第05节:链表
java·数据结构·spring boot·spring·链表·maven·intellij-idea