数据结构-队列的实现

举报
芒果_Mango 发表于 2022/02/26 21:33:49 2022/02/26
【摘要】 队列的基本概念队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表, 队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头 思考:用什么结构实现队列数组链表综上,我们选择用链表实现 1.0-队列结构==为了方便尾插,头删。我们定义两个指针标志头和尾==typedef ...

队列的基本概念

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

image.png


思考:用什么结构实现队列

数组

image.png


链表

image.png

综上,我们选择用链表实现


1.0-队列结构

==为了方便尾插,头删。我们定义两个指针标志头和尾==

image.png

typedef int QDataType;
//队列中的结构体
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QueueNode;

//存放指向结构体的两个指针
typedef struct Queue
{
	QueueNode* head;//指向链表的头
	QueueNode* tail;//指向链表的尾
}Queue;

1.1-初始化

image.png

最初:把两个指针置空

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

1.2-销毁

由于队列是用链表实现的

链表中每个结点都是malloc出来的,所以我们需要遍历把链表的结点释放掉

释放时要注意:

**1.要先保存下一个结点再释放 **

2.释放之后,把指向头的指针和指向尾的指针置空

//销毁
void QueueDestory(Queue* pq)
{
	assert(pq);
	//链表要遍历销毁结点,不能直接销毁
	QueueNode* cur = pq->head;
	while (cur)
	{
		//保存下一个结点
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = NULL;
	pq->tail = NULL;
}

1.3-队尾入数据

相当于尾插

==特殊情形:链表为空==(pq->head == NULL 或者 pq->tail == NULL)

此时,头指针和尾指针指向新结点


==普通情形:==

  • 1.开辟新结点 newnode
  • 2.尾指针和新结点进行链接 (pq->tail )
  • 3.新结点成为尾
//队尾入数据
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	//相当于尾插
	
	//构建新结点
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	newnode->next = NULL;
	newnode->data = x;
	//情况1:链表为空
	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;
	}

	//情况2:
	//tail newnode 
	else
	{
		pq->tail->next = newnode; //尾插
	//注意如果一开始没有数据,pq->tail = NULL,此时会出错,相当于对空指针解引用
	//所以没有数据时需要单独判断
		pq->tail = newnode;//指向新的尾
	}	
}

1.4-队头出数据

注意:要保证链表中还有数据(链表不为空)->即pq->head != NULL

队头出数据:

  • 先保存头结点的下一个结点,记为next结点
  • 释放头结点,然后head指向next结点

==注意点:删除最后一个结点时==

image.png

//队头出数据
void QueuePop(Queue* pq)
{
	assert(pq);
	//情况1:链表为空
	/*if (pq->head == NULL)
	{
		return -1;
	}*/
	assert(!QueueEmpty(pq));

	//情况2
	QueueNode* next = pq->head->next;//保存下一个结点
	free(pq->head);//释放队头
	pq->head = next;//next成为新的队头

	//注意!!!!如果一直删,删最后一个时候 此时next为NULL的,如果不把tail也置空,就会造成野指针
	if (pq->head == NULL)
	{
		pq->tail = NULL;
	}
}

1.5-取队头数据

注意:要保证链表有数据

返回头指针指向结点的数据

//取队头数据
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	//链表为空
	/*if (pq->head == NULL)
	{
		return -1;
	}*/
	assert(!QueueEmpty(pq));
	return pq->head->data;
}

1.6-取队尾数据

注意:要保证链表有数据

返回尾指针指向结点的数据

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

1.7-队列的长度

方法1:遍历链表进行统计

方法2:在定义结构体时,添加一个size变量

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
    int size ;//计算队列长度
}QueueNode;

后序我们插入数据:size++

出数据:size –

这样size标志的就是队列的长度


//队列的长度
int QueueSize(Queue* pq)
{
	assert(pq);
	//方法1:遍历统计
	//方法2:定义结构体时添加一个size变量,入数据:size++ 出数据size -- 用size标志队列长度

	//遍历统计
	QueueNode* cur = pq->head;
	int count = 0;
	while (cur)
	{
		count++;
		cur = cur->next;
	}
	return count;
}

1.8-判断队列是否为空

如果头指针或者尾指针为空->说明链表为空

//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	/*if (pq -> head == NULL)
	{
		return true;
	}
	else
	{
		return false;
	}*/
	return pq->head == NULL;
}

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。