当前位置:   article > 正文

数据结构之队列详解_数据结构 队列详解

数据结构 队列详解

数据结构之队列详解

在这里插入图片描述



前言

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


一、队列的概念及结构

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

二、队列的实现

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

1.基本结构

代码如下(示例):

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

2.基本操作

(1)初始化和销毁

  • 初始化只需要把头尾置空即可,但是销毁不仅仅要销毁队列头尾指针,还要释放每一个存放数据的节点
// 初始化队列
void QueueInit(Queue* q)
{
	assert(q);
	q->front = q->tail = NULL;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
// 销毁队列
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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

(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;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 出队列时候需要特殊注意一种情况,正常做法是把头节点出队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;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

(3)判空

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

(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;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
代码如下(示例):

三、循环队列

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

总结

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/915502
推荐阅读
相关标签
  

闽ICP备14008679号