队列的介绍与实现(详解)

队列的介绍

队列的概念

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

入队列:队列的插入操作叫做入队列,进行插入操作的一端称为队尾。

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

队列的结构

在这里插入图片描述

生活中队列的运用实例

队列在生活中的运用非常广泛。很大一部分医院、营业厅以及餐厅等场所都存在队列的应用。
例如,医院的采血环节的流程就运用了队列。在医院,如果我们要去抽血,我们首先要在旁边的抽号机抽取自己的编号,当某一个抽血窗口叫到你时,你便可以去抽血了。
在这个过程中,当你在抽号机抽取到某一个编号,那么这个编号这时就从队尾入队列,当某一窗口抽血结束后,会在该队列中拿走一个编号并叫该编号的人到这个窗口接受抽血,那么这时这个编号就从队头出队列
在这里插入图片描述

队列的实现

初始化队列

首先我们需要创建一个结点类型,类型包含了该结点的数据和指向下一结点的指针。

typedef int QDataType;//队列中存储的元素类型(这里用整型举例)

typedef struct QListNode
{
	struct QListNode* next;//指针域
	QDataType data;//数据域
}QListNode;

队列与普通链表又有所不同,普通链表只需要知道链表的头指针,而队列的信息包括了队头和队尾,所以我们需要再创建一个结构体用于存放队列的队头和队尾。

typedef struct Queue
{
	QListNode* head;//队头
	QListNode* tail;//队尾
}Queue;

然后,我们需要一个初始化函数,对刚创建的队列进行初始化。

//初始化队列
void QueueInit(Queue* pq)
{
	assert(pq);
	//起始时队列为空
	pq->head = NULL;
	pq->tail = NULL;
}

销毁队列

队列中的每一个结点所占用的内存空间都是动态开辟的,当我们使用完队列后需要及时释放队列中的每一个结点。

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

	QListNode* cur = pq->head;//接收队头
	//遍历链表,逐个释放结点
	while (cur)
	{
		QListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = NULL;//队头置空
	pq->tail = NULL;//队尾置空
}

队尾入队列

入队列,即申请一个新结点并将其链接到队尾,然后改变队尾的指针指向即可。需要注意的是:若队列中原本无数据,那么我们只需让队头和队尾均指向这个新申请的结点即可。

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

	QListNode* newnode = (QListNode*)malloc(sizeof(QListNode));//申请新结点
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	newnode->data = x;//新结点赋值
	newnode->next = NULL;//新结点指针域置空
	if (pq->head == NULL)//队列中原本无结点
	{
		pq->head = pq->tail = newnode;//队头、队尾直接指向新结点
	}
	else//队列中原本有结点
	{
		pq->tail->next = newnode;//最后一个结点指向新结点
		pq->tail = newnode;//改变队尾指针指向
	}
}

队头出队列

出队列,即释放队头指针指向的结点并改变队头指针的指向即可。若队列中只有一个结点,那么直接将该结点释放,然后将队头和队尾置空即可。

//队头出队列
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));//检测队列是否为空

	if (pq->head->next == NULL)//队列中只有一个结点
	{
		free(pq->head);
		pq->head = NULL;
		pq->tail = NULL;
	}
	else//队列中有多个结点
	{
		QListNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;//改变队头指针指向
	}
}

获取队列头部元素

获取队列头部元素,即返回队头指针指向的数据即可。

//获取队列头部元素
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));//检测队列是否为空

	return pq->head->data;//返回队头指针指向的数据
}

获取队列尾部元素

获取队列尾部元素,即返回队尾指针指向的数据即可。

//获取队列尾部元素
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));//检测队列是否为空

	return pq->tail->data;//返回队尾指针指向的数据
}

检测队列是否为空

检测队列是否为空,即判断队头指针指向的内容是否为空。

//检测队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->head == NULL;
}

获取队列中有效元素个数

队列中有效元素个数,即队列中的结点个数。我们只需遍历队列,统计队列中的结点数并返回即可。

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

	QListNode* cur = pq->head;//接收队头
	int count = 0;//记录结点个数
	while (cur)//遍历队列
	{
		count++;
		cur = cur->next;
	}
	return count;//返回队列中的结点数
}
已标记关键词 清除标记
相关推荐
<p> <span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002191047226381.jpg" alt="" /><br /> </span> </p> <p> <span style="font-size:18px;"><br /> </span> </p> <p> <span style="font-size:18px;">【课程介绍】</span> </p> <span style="font-size:18px;">     课程目标:</span><br /> <span style="font-size:18px;">             - 深入理解RabbitMQ发送消息的模式</span><br /> <span style="font-size:18px;">             - 熟练使用RabbitMQ五种消息模型</span><br /> <span style="font-size:18px;">             - 如何确定RabbitMQ的消息是否发送成功</span><br /> <span style="font-size:18px;">             - 如何确定RabbitMQ发送的消息是否消费成功。</span><br /> <span style="font-size:18px;">             - 项目实战中如何使用RabbitMQ,以及RabbitMQ的作用</span><br /> <br /> <span style="font-size:18px;">    消息队列是典型的:生产者、消费者模型。生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。因为消息的生产和消费都是异步的,而且只关心消息的发送和接收,没有业务逻辑的侵入,这样就实现了生产者和消费者的解耦。</span><br /> <br /> <span style="font-size:18px;">结合前面所说的问题:</span><br /> <br /> <span style="font-size:18px;">- 商品服务对商品增删改以后,无需去操作索引库或静态页面,只是发送一条消息,也不关心消息被谁接收。</span><br /> <span style="font-size:18px;">- 搜索服务和静态页面服务接收消息,分别去处理索引库和静态页面。</span><br /> <br /> <span style="font-size:18px;">如果以后有其它系统也依赖商品服务的数据,同样监听消息即可,商品服务无需任何代码修改。</span><br /> <span style="font-size:18px;"></span>
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页