数据结构之队列

目录

队列的概念及其结构

队列的实现 

队列的初始化

队列的删除操作(队头出队列 )

获取队头元素

获取队尾元素 

获取队列中有效元素的个数

检查队列是否为空
​​​​​​​

队列的概念及其结构

只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出

FIFO(First In First Out) 。

入队列:进行插入操作的一端称为队尾; 出队列:进行删除操作的一端称为队头。

其实队列跟我们现实生活中的排队差不多。你要进入这个队伍,你是不是要从队尾排,出去是不是从队头处。也就是我们在餐厅买饭,在队尾排队(队列的插入),轮到你的时候,你也就是这个队的队头了,然后打好饭就直接从队头走了(队列的删除操作)。 

队列的实现 

队列也可以用数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,也就是当删除数据时,需要挪动数据,效率会比较低。因此我们可以优先选择单链表(无头单向非循环链表)实现队列。

为了提高效率,我们可以分别定义一个头指针phead、尾指针ptail。让phead指向单链表(队列)的头结点,让ptail指向单链表(队列)的尾结点。

队列需要定义两个结构体。第一个要定义结点结构,即是每一个结点。定义的结点结构包含结构体的指针域和数据域。

第二个结构体是将头指针phead和尾指针ptail,和队列的成员数量size封装起来,定义在结构体中。定义的第二个结构体其实就是为了能够提高插入删除的效率,不用穿太多的参数。phead、ptail是结构体的成员,是结构体成员内部,改变的是结构体。

typedef int SQDataType;
//定义结点结构
typedef struct QueueNode
{
	SQDataType data;//存储节点的数据
	struct QueueNode* next;//存储节点的地址
}QNode;
//将头指针phead和尾指针ptail封装起来
typedef struct Queue
{
	QNode* phead;//链表头指针
	QNode* ptail;//链表尾指针
	int size;//数量
}Queue;

队列的初始化

首先就是队列的初始化,让队列为空。 

void SQInit(Queue* pq)
{
	assert(pq);//传个结构体指针过来,结构体外面肯定已经开辟好,所以不为空
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;//成员数量初始化为0
}

队列的插入操作(队尾入队列) 

要在一个队列中插入一个数据,首先要开辟一个新结点newnode,让newnode的数据域存储需要插入的数据,因为是在队列的队尾插入,所以newnode会成为新的队尾,即指针域置为空。因为在队列中新插入了一个结点,所以队列中的成员数量会加一(size++)

插入分两种情况:一是:插入的队列为空。二是:插入的队列不为空。

当插入的队列为空时:头指针和尾指针会指向队列内的唯一一个结点,即指向同一个结点。

pq->phead = pq->ptail = newnode;最后队列的成员数量加一

当插入的队列不为空时:pq->ptail->next会线连接上newnode,即插入的newnode会成为新的尾结点,pq->ptail指向新的尾结点(pq->ptail = newnode),队列的成员数量加一

void SQPush(Queue* pq, SQDataType x)
{
	assert(pq);
	//开辟一个新节点newnode,newnode的数据域就是需要插入的x,指针域为空,因为是尾结点
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;//newnode的数据域为x
	newnode->next = NULL;//newnode的指针域为空
	//队列为空时
	if (pq->phead == NULL)
	{
		assert(pq->ptail == NULL);
		pq->phead = pq->ptail = newnode;
	}
	else
		//队列不为空时
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;//出入一个节点,成员数量+1
}

队列的删除操作(队头出队列 )

首先要进行队列的删除操作时,队列不能为空。其次要判断队列中有一个结点还是多个结点。

情况一:队列中只有一个结点时 ,pq->phead->next = NULL;释放掉这一个节点,队列就为空了,pq->phead = pq->ptail = NULL;成员数量减一(size--)。

情况二:队列中有多个节点时,释放掉头结点,头指针会指向头结点的下一个位置,成为新的头结点。成员数量减一(size--)。

void SQPop(Queue* pq)
{
	assert(pq);
	assert(!SQEmpty(pq));//队列为空不能删
	//队列只有一个结点时
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
		//队列有多个结点时
	{
		QNode* next = pq->phead->next;//记录头结点的下一个位置
		free(pq->phead);//释放掉头结点
		pq->phead = next;//头指针指向下一个节点,即next成为新的头结点
	}
	pq->size--;//成员数量-1
}

获取队头元素

队列不能为空,直接返回队列的第一个元素就可以了,非常简单。

SQDataType SQFront(Queue* pq)
{
	assert(pq);
	assert(!SQEmpty(pq));//队列不能为空
	return pq->phead->data;//返回队头数据
}

获取队尾元素 

队列不能为空,直接返回队列的最后一个元素就可以了,非常简单。

SQDataType SQBack(Queue* pq)
{
	assert(pq);
	assert(!SQEmpty(pq));//队列不能为空
	return pq->ptail->data;//返回队尾数据
}

获取队列中有效元素的个数

直接返回元素个数就可以了,也就是size

int SQSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

检查队列是否为空

直接判断size == 0,就可以了。也可以判断头指针和尾指针是不是都是指向空。

布尔类型,为空返回true,不为空返回false。

bool SQEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值