数据结构——队列

目录

一、队列是什么

二、队列的实现

1、队列的基本结构

2、队列的初始化

3、队列的插入

4、队列的删除

5、返回队列的队头数据

6、返回队列的队尾数据

7、判定队列是否为空

8、返回队列元素个数

9、队列的遍历

10、队列的释放


一、队列是什么

队列,它只允许在一端进行插入操作,一端进行删除操作,队列具有先进先出FIFO(First In First Out)的特性。

入队列: 进行插入操作的一端称为队尾

出队列: 进行删除操作的一端称为队头

举个栗子:进队列的顺序是1,2,3,4,5。那么出队列的顺序也必然是1,2,3,4,5

二、队列的实现

队列如果要入数据,只能从队列的尾部入,如果要出数据只能从队头出,那么必然涉及到大量的尾插和头删。

用顺序表

顺序表尾插还可以,但是顺序表的尾删要挪动数据,效率不是很高,那么还有没有更优的实现方案呢?

用链表

头删,链表是很擅长的,但是尾插呢?尾插需要遍历链表,找到最后一个节点,然后插入,效率不是也不高吗?此时我们可以定义一个尾节点来解决这个问题,直接插入到尾节点的后面,更新尾节点到下一个位置即可。

1、队列的基本结构

既然要用链表,那肯定要有一个个的节点,我们可以用结构体来定义,接下来我们需要一个头节点和一个尾节点,还有当前队列的数据个数,多个数据,我们最好再用结构体封装起来。

cpp 复制代码
typedef int QTDataType;

typedef struct QNode
{
	struct QNode* next;
	QTDataType val;
}QNode;

typedef struct Queue
{
	QNode* head; // 队列头节点
	QNode* tail; // 队列尾节点
	int size;	 // 队列数据个数
}Queue

2、队列的初始化

将头节点和尾节点初始化为NULL,size初始化为0。

cpp 复制代码
void QInit(Queue* q)
{
	q->head = q->tail = NULL;
	q->size = 0;
}

3、队列的插入

队列只能从一端进行插入,也就是从尾部进行插入。那么我们需要先malloc申请一个新节点newnode。之后判定是否是第一次入队列,第一次入队列head和tail都是NULL,需要将head和tail都置为newnode,如果不是第一次,直接在tail后面尾插,然后更新tail和size

cpp 复制代码
void QPush(Queue* q, QTDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->val = x;
	newnode->next = NULL;
    //第一次入队列,队列为NULL,特殊处理
	if (q->head == NULL)
	{
		q->head = q->tail = newnode;
	}
	else
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;
}

4、队列的删除

队列的删除就是头删,头删先记录一下队列头部的下一个节点,然后free掉头结点,更新头节点即可,但是,如果队列只有一个节点,tail指向head已经释放的节点,就野指针了,因此需要特殊处理只有一个节点的情况:free掉head节点,并将head和tail都置NULL。要判断队列是否为空,为空是删除不了的,直接暴力一点报错。

cpp 复制代码
void QPop(Queue* q)
{
	assert(q);
	assert(q->head != NULL);
	// 只有一个节点
	if (q->head->next == NULL)
	{
		free(q->head);
		q->head = q->tail = NULL;
	}
	//两个及以上节点
	else 
	{
		
		QNode* next = q->head->next; // 记录头的下一个节点
		free(q->head); //释放掉头节点
		q->head = next; //让头节点指向下一个
	}
	q->size--;
}

5、返回队列的队头数据

将head的val返回即可,但是要判定一下队列不为空。

cpp 复制代码
QTDataType QFront(Queue* q)
{
	assert(q);
	assert(q->head != NULL);

	return q->head->val;
}

6、返回队列的队尾数据

将tail的val返回即可,同样判定一下队列不为空,队列是先进先出的,1,2,3,4,5进了只能以1,2,3,4,5的顺序出。那返回队尾元素有啥意义呢?队尾元素在某些情况下是非常有意义的,比如说用队列实现栈这道题。用队列实现栈

cpp 复制代码
QTDataType QBack(Queue* q)
{
	assert(q);
	return q->tail->val;
}

7、判定队列是否为空

判定head是否为空即可

cpp 复制代码
bool QEmpty(Queue* q)
{
	return q->head == NULL;
}

8、返回队列元素个数

返回size即可。

cpp 复制代码
int QSize(Queue* q)
{
	return q->size;
}

9、队列的遍历

队列的遍历和栈是非常相似的,打印对头数据,然后出队。

cpp 复制代码
#include "queue.h"

int main()
{
	Queue q;
	QInit(&q);

	QPush(&q, 1);
	QPush(&q, 2);
	QPush(&q, 3);
	QPush(&q, 4);
	QPush(&q, 5);


	while (!QEmpty(&q))
	{
		printf("%d\n", QFront(&q));
		QPop(&q);
	}

	QDestory(&q);
	return 0;
}

10、队列的释放

cpp 复制代码
void QDestory(Queue* q)
{
	assert(q);
	QNode* cur = q->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}

	q->head = q->tail = NULL;
	q->size = 0;
}
相关推荐
xiangyun612 小时前
【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清
c语言·开发语言·数据结构·c++·算法
xiangyun612 小时前
【408数据结构 06】双链表、循环链表、静态链表
c语言·开发语言·数据结构·c++·算法
OKkankan4 小时前
LangChain 能力详解!:输出解析、RAG、向量数据库与 Retriever 检索器
数据结构·python·langchain·ai应用
蓝速科技4 小时前
便民服务大厅 AI 数字人一体机场景适配与落地指南丨蓝速科技
大数据·网络·数据结构·人工智能·自然语言处理·数据分析·运维开发
xxwxx__4 小时前
C++ AVL 树深度剖析:平衡二叉搜索树原理、源码与面试考点
数据结构·c++
Logic1014 小时前
C语言/数据结构数组题解:数字列表加一(Plus One)——进位处理与数组扩展
c语言·数据结构·模拟·数组·时间复杂度·算法题·进位
Escalating_xu4 小时前
【C语言常见概念】从第一行代码到字符串结束标志:一次打通编译、main、ASCII、转义字符与注释
c语言·c++
Navigator_Z5 小时前
LeetCode //C - 1250. Check If It Is a Good Array
c语言·算法·leetcode
SuperByteMaster6 小时前
freertos 任务创建方式
c语言
susplus7 小时前
【传感器DS18B20】51单片机上实现温度采集
c语言·51单片机·ds18b20·温度采集