数据结构——队列——一篇就够了

队列

队列的概念及结构

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

队列的实现

队列可以数组也可以链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低(如果数组要出数据,那么就要挪动数据)。
下面我们用链表的方式实现队列

1.初始化队列

1).创建链表节点
链表需要有节点,节点与节点之间进行链接,节点中包含数据与下一个结点的地址。

typedef int QDataType;//   插入数据的类型
typedef struct QueueNode
{
	struct QueueNode* next;// 指针域
	QDataType data;// 数据域
}QueueNode;

2).链表式队列与单链表有所不同,后者只需要头指针指向链表第一个节点即可(不需要尾指针,虽然可以有尾指针,但是作用不是很明显);前者需要两个指针,一个是头指针,一个是尾指针,两个变量以上,就可以用结构体的形式,把两个指针包装起来了,这样更方便使用,不用结构体也可以。两个指针相当于出口和入口的关系。队列由两个指针控制了。

typedef struct Queue
{
	QueueNode* head;
	QueueNode* tail;
}Queue;

3).创建初始化函数
对刚刚创建的结构体Queue进行初始化

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}

2.销毁队列

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

//队列销毁
//销毁队列
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;//队尾置空
}

3.检测队列是否为空

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

//判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL && pq->tail==NULL;
}

4.队尾入队列

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

// 进队列
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		printf("fail QueuePush	");
		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;
	}
}

5.出队列

出队列只能从对头开始出,这样才符合队列的特性,
出队列,即释放队头指针指向的结点并改变队头指针的指向即可。
若队列中只有一个结点,那么直接将该结点释放,然后将队头和队尾置空即可。

// 出队列
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));//检查队列是否为空,如果是则断言
	QueueNode*next = pq->head->next;// 记录下一个结点
	free(pq->head);// 释放头节点空间
	pq->head = next;// 头指针指向前一个节点
	if (pq->head == NULL)// tail 指向的空间被释放了,但是tail还是指向那个空间,造成非法访问
		//预防野指针
		if (pq->head == NULL)
		{
			pq ->tail = NULL;
		}
}

6.获取队列头部元素

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

// 取对头的数据
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}

7.获取队列尾部元素

//取队尾的数据
QDataType QueueBack(Queue * pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;

};

8.获取队列中有效元素个数

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

//队列的大小
int QueueSize(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	int count = 0;
	QueueNode* cur = pq->head;
	while (cur)
	{
		count++;
		cur = cur->next;
	}
	return count;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2023框框

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值