数据结构之队列详解

Posted 梦乡回雪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构之队列详解相关的知识,希望对你有一定的参考价值。

数据结构之队列详解



前言

在介绍玩栈之后我们来介绍下队列基本结构


一、队列的概念及结构

  • 队列:只允许在『 一端 』进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有『 先进先出 』 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头
  • 上图演示:

二、队列的实现

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

1.基本结构

代码如下(示例):

// 链式结构:表示队列
typedef struct QListNode
{ 
	 struct QListNode* _pNext; 
	 QDataType _data; 
}QNode; 
// 队列的结构
typedef struct Queue
{ 
	 QNode* _front; 
	 QNode* _rear; 
}Queue;
  • 这里注意QListNode表示的是每一个『 存放数据 』的节点,Queue是『 整个队列 』,含有指向队头和队尾的两个QListNode* 指针。因此我们在函数传参的时候只需要传递Queue相关的地址来操作队列即可

2.基本操作

(1)初始化和销毁

  • 初始化只需要把头尾置空即可,但是销毁不仅仅要销毁队列头尾指针,还要释放每一个存放数据的节点
// 初始化队列
void QueueInit(Queue* q)
{
	assert(q);
	q->front = q->tail = NULL;
}
// 销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);
	QueueNode* cur = q->front;
	while (cur)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}	
	q->front = q->tail = NULL;
}

(2)出队入队

  • 队尾入队列,考虑两种情况,一是队列为空直接队列头尾指针指向新节点,二是不为空,需要链接新节点到尾部
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	newnode->data = data;
	newnode->next = NULL;
	if (q->front == NULL)
	{
		q->front = q->tail = newnode;
	}
	else
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
}
  • 出队列时候需要特殊注意一种情况,正常做法是把头节点出队free掉,并且头指针指向下一个,但是要考虑只有一个数据出队时候!!!当你头指针释放完指空的时候此刻,尾指针还在指向释放掉的空间,成了野指针!!!因此要置空。
// 队头出队列
void QueuePop(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));

	QueueNode* next = q->front->next;
	free(q->front);
	q->front = next;
	if (q->front == NULL)
	{
		q->tail = NULL;
	}
}

(3)判空

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

(4)获取元素

// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
	assert(q);//断言防止传进来空指针
	assert(!QueueEmpty(q));//断言防止队列空
	return q->front->data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->tail->data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
	assert(q);
	int n = 0;
	QueueNode* cur = q->front;
	while (cur)
	{
		cur = cur->next;
		n++;
	}
	return n;
}

代码如下(示例):

三、循环队列

  • 实际中我们有时还会使用一种队列叫循环队列。环形队列可以使用数组实现也可以用循环链表来实现
  • 当头指针和尾指针相遇时队列已满,具体可以参考这篇文章

总结

以上就是队列基础内容和操作,实际上栈和队列的实际应用还是很多,比如叫号机等等。那么队列和栈的常见题型下次见。

以上是关于数据结构之队列详解的主要内容,如果未能解决你的问题,请参考以下文章

数据结构之队列超详解

多线程之阻塞队列BlockingQueue详解

Python实现的数据结构与算法之队列详解

Kafka 设计详解之队列

六:抽象队列同步器AQS应用之BlockingQueue详解

AQS 详解之共享锁模式