队列与循环队列

news2025/1/4 16:49:47

目录

1. 前言:

2. 队列

2.1 队列的概念

2.2 队列的实现

2.3 队列的声明

2.4 队列的初始化

2.5 队列的入队

2.6 队列的出队

2.7 队列获取队头元素

2.8 队列获取队尾元素

2.9 队列获取有效数据个数

2.10 队列判断是否为空

2.11 打印队列

2.12 销毁队列

3. 队列完整代码

3.1 Queue.h

3.2 Queue.c

4. 循环队列

4.1 循环队列的概念

​编辑4.2 循环队列的实现

4.3 循环队列的声明

4.4 循环队列的初始化

4.5 循环队列判空

 4.6 循环队列判满

4.7 循环队列入队

4.8 循环队列出队

4.9 循环队列获取队头数据

4.10 循环队列获取队尾数据

4.11 循环队列获取有效数据个数

4.12 循环队列销毁

5. 循环队列完整代码

5.1 CircularQueue.h

5.2 CircularQueue.c


1. 前言:

在之前我们学习了栈,我们知道栈的特点是后进先出,我们今天学习的队列,它是先进先出的

2. 队列

2.1 队列的概念

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

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

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

2.2 队列的实现

其实队列和栈一样,也是可以使用顺序表和单链表来实现的,这里本章主要讲述使用单链表来实现队列。

Queue.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int QDataType;

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}qn;

typedef struct Queue
{
	//记录队头
	qn* phead;
	//记录队尾
	qn* ptail;
	//记录队列有效数据个数
	int size;
}q;

//初始化队列
void QInit(q* pq);
//入队
void QPush(q* pq, QDataType x);
//出队
void QPop(q* pq);
//获取队头元素
QDataType QFront(q* pq);
//获取队尾元素
QDataType QBack(q* pq);
//获取队列内有效数据个数
int QSize(q* pq);
//判断队列是否为空
bool QEmpty(q* pq);
//打印队列
void QPrint(q* pq);
//销毁队列
void QDestroy(q* pq);

2.3 队列的声明

Queue.h

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}qn;

typedef struct Queue
{
	//记录队头
	qn* phead;
	//记录队尾
	qn* ptail;
	//记录队列有效数据个数
	int size;
}q;

这里我们跟链式栈的声明方式一样,使用了两个结构体,一个结构体用来声明节点的结构,一个结构体声明队列的结构,这里在队列结构中,我们增加指向队头和队尾的指针和计数的size,这样可以方便我们迅速的找到队头数据和队尾数据还有队内有效数据个数。

2.4 队列的初始化

Queue.c

void QInit(q* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

2.5 队列的入队

Queue.c

void QPush(q* pq, QDataType x)
{
	assert(pq);
	qn* newnode = (qn*)malloc(sizeof(qn));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}

2.6 队列的出队

void QPop(q* pq)
{
	assert(pq);
	assert(pq->size > 0);
	//只有一个节点
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	//多个节点
	else
	{
		qn* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}

2.7 队列获取队头元素

Queue.c

QDataType QFront(q* pq)
{
	assert(pq);
	assert(pq->size > 0);

	return pq->phead->data;
}

2.8 队列获取队尾元素

Queue.c

QDataType QBack(q* pq)
{
	assert(pq);
	assert(pq->size > 0);

	return pq->ptail->data;
}

2.9 队列获取有效数据个数

Queue.c

int QSize(q* pq)
{
	assert(pq);

	return pq->size;
}

2.10 队列判断是否为空

Queue.c

bool QEmpty(q* pq)
{
	assert(pq);

	return pq->size == 0;
}

2.11 打印队列

Queue.c

void QPrint(q* pq)
{
	assert(pq);
	while (!QEmpty(pq))
	{
		printf("%d ", QFront(pq));
		QPop(pq);
	}
}

2.12 销毁队列

Queue.c

void QDestroy(q* pq)
{
	assert(pq);
	qn* pcur = pq->phead;
	while (pcur)
	{
		qn* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;

}

3. 队列完整代码

3.1 Queue.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int QDataType;

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}qn;

typedef struct Queue
{
	//记录队头
	qn* phead;
	//记录队尾
	qn* ptail;
	//记录队列有效数据个数
	int size;
}q;

//初始化队列
void QInit(q* pq);
//入队
void QPush(q* pq, QDataType x);
//出队
void QPop(q* pq);
//获取队头元素
QDataType QFront(q* pq);
//获取队尾元素
QDataType QBack(q* pq);
//获取队列内有效数据个数
int QSize(q* pq);
//判断队列是否为空
bool QEmpty(q* pq);
//打印队列
void QPrint(q* pq);
//销毁队列
void QDestroy(q* pq);

3.2 Queue.c

#include"Queue.h"

void QInit(q* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

void QPush(q* pq, QDataType x)
{
	assert(pq);
	qn* newnode = (qn*)malloc(sizeof(qn));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}

void QPop(q* pq)
{
	assert(pq);
	assert(pq->size > 0);
	//只有一个节点
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	//多个节点
	else
	{
		qn* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}

QDataType QFront(q* pq)
{
	assert(pq);
	assert(pq->size > 0);

	return pq->phead->data;
}

QDataType QBack(q* pq)
{
	assert(pq);
	assert(pq->size > 0);

	return pq->ptail->data;
}

int QSize(q* pq)
{
	assert(pq);

	return pq->size;
}

bool QEmpty(q* pq)
{
	assert(pq);

	return pq->size == 0;
}

void QPrint(q* pq)
{
	assert(pq);
	while (!QEmpty(pq))
	{
		printf("%d ", QFront(pq));
		QPop(pq);
	}
}

void QDestroy(q* pq)
{
	assert(pq);
	qn* pcur = pq->phead;
	while (pcur)
	{
		qn* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;

}

4. 循环队列

4.1 循环队列的概念

循环队列:循环队列是一种线性数据结构,其操作表示基于FIFO(先进先出)原则,并且队尾被连接在队头之后以形成一个循环,前提是它的空间大小是固定的。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

简单来说就是:有限的空间,保证先进先出,重复使用。

4.2 循环队列的实现

CircularQueue.h


#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

#define k 4

typedef int CQDataType;

typedef struct CircularQueue
{
	CQDataType* arr;
	int front;//指向队头
	int rear;//指向队尾的下一个位置
}cq;

//初始化
void CqInit(cq* pcq);
//判空
bool CqEmpty(cq* pcq);
//判满
bool CqFull(cq* pcq);
//入队
void CqPush(cq* pcq, CQDataType x);
//出队
void CqPop(cq* pcq);
//获取队头数据
CQDataType CqFront(cq* pcq);
//获取队尾数据
CQDataType CqBack(cq* pcq);
//获取队列有效数据个数
int CqSize(cq* pcq);
//销毁队列
void CqDestroy(cq* pcq);

 在这里我们实现循环队列是基于顺序表的情况下实现。

我们首先思考一下,我们怎么判断循环队列是空还是满。

4.3 循环队列的声明

#define k 4

typedef int CQDataType;

typedef struct CircularQueue
{
	CQDataType* arr;
	int front;//指向队头
	int rear;//指向队尾的下一个位置
}cq;

这里我们需要是一个静态的队列,所以我们用#define来声明一个值。这里arr是指向动态开辟内存的一块空间,front指向循环队列的队头,rear指向循环队列队尾的下一个位置。

4.4 循环队列的初始化

void CqInit(cq* pcq)
{
	assert(pcq);
	//多开辟一个空间,避免出现循环队列假溢出的问题
	CQDataType* tmp = (CQDataType*)malloc(sizeof(CQDataType) * (k + 1));
	if (tmp == NULL)
	{
		perror("malloc");
		exit(1);
	}
	pcq->arr = tmp;
	pcq->front = pcq->rear = 0;
}

4.5 循环队列判空

bool CqEmpty(cq* pcq)
{
	assert(pcq);
	//头和尾相等表示空
	return pcq->front == pcq->rear;
}

 4.6 循环队列判满

bool CqFull(cq* pcq)
{
	assert(pcq);
	//尾+1再模k+1解决了回绕问题
	return (pcq->rear + 1) % (k + 1) == pcq->front;
}

4.7 循环队列入队

void CqPush(cq* pcq, CQDataType x)
{
	assert(pcq);
	//判断循环队列是否满了
	assert(!CqFull(pcq));
	pcq->arr[pcq->rear++] = x;
	//解决了循环队列回绕的问题
	pcq->rear %= (k + 1);
}

4.8 循环队列出队

void CqPop(cq* pcq)
{
	assert(pcq);
	//判断循环队列是否为空
	assert(!CqEmpty(pcq));

	pcq->front++;

	pcq->front %= (k + 1);
}

4.9 循环队列获取队头数据

CQDataType CqFront(cq* pcq)
{
	assert(pcq);
	assert(!CqEmpty(pcq));

	return pcq->arr[pcq->front];
}

4.10 循环队列获取队尾数据

这里我们再获取循环队列队尾数据的时候,不是尾-1,当尾在0这个位置的时候,-1就是-1了,下标是不能访问-1的,所以我们这里有两种写法,可以写成pcq->rear == 0 ? 4 : pcq->rear-1,利用三目操作符进行判断。或者先让他-1再模k+1,最后整体在模k+1。

CQDataType CqBack(cq* pcq)
{
	assert(pcq);
	assert(!CqEmpty(pcq));

	return pcq->arr[(pcq->rear - 1+ k+1) % (k + 1)];
}

4.11 循环队列获取有效数据个数

这里计算循环队列中有效数据个数也不能直接返回rear,rear也不是代表size,这里当rear在front右边时,需要rear-front,当rear在front在边时,需要((rear-front)+(k+1))%(k+1))。其实rear在front右边时,也可与写成在左边的写法。当值小于k+1的时候,模k+1并没有影响。

int CqSize(cq* pcq)
{
	assert(pcq);
	if (CqEmpty(pcq))
	{
		return 0;
	}
	return ((pcq->rear - pcq->front) + (k + 1)) % (k + 1);
}

4.12 循环队列销毁

void CqDestroy(cq* pcq)
{
	assert(pcq);
	free(pcq->arr);
	pcq->arr = NULL;
	pcq->front = pcq->rear = 0;
}

5. 循环队列完整代码

5.1 CircularQueue.h


#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

#define k 4

typedef int CQDataType;

typedef struct CircularQueue
{
	CQDataType* arr;
	int front;//指向队头
	int rear;//指向队尾的下一个位置
}cq;

//初始化
void CqInit(cq* pcq);
//入队
void CqPush(cq* pcq, CQDataType x);
//出队
void CqPop(cq* pcq);
//判空
bool CqEmpty(cq* pcq);
//判满
bool CqFull(cq* pcq);
//获取队头数据
CQDataType CqFront(cq* pcq);
//获取队尾数据
CQDataType CqBack(cq* pcq);
//获取队列有效数据个数
int CqSize(cq* pcq);
//销毁队列
void CqDestroy(cq* pcq);

5.2 CircularQueue.c

#include"CircularQueue.h"

void CqInit(cq* pcq)
{
	assert(pcq);
	//多开辟一个空间,避免出现循环队列假溢出的问题
	CQDataType* tmp = (CQDataType*)malloc(sizeof(CQDataType) * (k + 1));
	if (tmp == NULL)
	{
		perror("malloc");
		exit(1);
	}
	pcq->arr = tmp;
	pcq->front = pcq->rear = 0;
}

void CqPush(cq* pcq, CQDataType x)
{
	assert(pcq);
	//判断循环队列是否满了
	assert(!CqFull(pcq));
	pcq->arr[pcq->rear++] = x;
	//解决了循环队列回绕的问题
	pcq->rear %= (k + 1);
}

bool CqEmpty(cq* pcq)
{
	assert(pcq);
	//头和尾相等表示空
	return pcq->front == pcq->rear;
}

bool CqFull(cq* pcq)
{
	assert(pcq);
	//尾+1再模k+1解决了回绕问题
	return (pcq->rear + 1) % (k + 1) == pcq->front;
}


void CqPop(cq* pcq)
{
	assert(pcq);
	//判断循环队列是否为空
	assert(!CqEmpty(pcq));

	pcq->front++;

	pcq->front %= (k + 1);
}


CQDataType CqFront(cq* pcq)
{
	assert(pcq);
	assert(!CqEmpty(pcq));

	return pcq->arr[pcq->front];
}

CQDataType CqBack(cq* pcq)
{
	assert(pcq);
	assert(!CqEmpty(pcq));

	return pcq->arr[(pcq->rear - 1+ k+1) % (k + 1)];
}

int CqSize(cq* pcq)
{
	assert(pcq);
	if (CqEmpty(pcq))
	{
		return 0;
	}
	return ((pcq->rear - pcq->front) + (k + 1)) % (k + 1);
}

void CqDestroy(cq* pcq)
{
	assert(pcq);
	free(pcq->arr);
	pcq->arr = NULL;
	pcq->front = pcq->rear = 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1865380.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器发货到菲律宾的完整流程 广东智慧物流

机器发货到菲律宾的完整流程 广东智慧物流 &#x1f31f;【机器发货到菲律宾完全攻略】&#x1f31f; 机器发货到菲律宾的完整流程 广东智慧物流 为你整理了一份超详细的机器发货到菲律宾的攻略&#xff01;海运14天轻松到达&#xff0c;让你无后顾之忧&#xff01;&#x1f…

【编译原理】总览

1 字母表 字母表&#xff1a; 用∑表示&#xff0c;它是一个有穷符号集合 符号&#xff1a;字母、数字、标点符号... 例如&#xff1a;二进制字母表为{0&#xff0c;1}&#xff0c;ASCII字符集 2 字母表的运算 字母表上的乘积&#xff1a; ∑1∑2{ab | a属于∑1&#xff0c;b…

MySQL—存储过程(详细介绍与基本语法)

目录 一、存储过程——介绍 &#xff08;1&#xff09;基本介绍 &#xff08;2&#xff09;基本特点 二、存储过程——语法 &#xff08;1&#xff09;基本语法 创建 调用 &#xff08;2&#xff09;实操&#xff08;创建和调用&#xff09; 1、创建一个叫 "p1&qu…

SAP CO11N BAPI_PRODORDCONF_CREATE_TT连续报工异步更新导致COGI解决方案

背景&#xff1a; 之前上一个项目上有同事碰到一个问题&#xff0c;外围接口数据进入SAP&#xff0c;可能会对同一工单同一工序进行连续多次报工&#xff0c;并且工序控制码配置的是会自动货物移动的&#xff0c;所以正常来说&#xff0c;调用完BAPI完之后除了报工数量会更新之…

indexedDB---浏览器本地数据库实现增删改查

关于indexedDB indexedDB的基本使用&#xff0c;可以参考&#xff1a;indexedDB---掌握浏览器内建数据库的基本用法_indexdb浏览器使用-CSDN博客 indexedDB是浏览器本地数据库&#xff0c;既然是数据库就能够实现增删改查&#xff0c;了解了indexedDB的基本使用后&#xff0c…

怎么把不同的文件做成二维码?多种文件类型在线生码的制作方法

扫码来展示文件是现在很多场景下会使用的一种内容展示方法&#xff0c;这种方式能够简化其他人获取文件的流程&#xff0c;从而提升文件传播的效率&#xff0c;用户可以存储二维码&#xff0c;随时扫码查看文件内容。文件生成二维码支持多种类型的文件使用&#xff0c;比如ppt、…

Element 页面滚动表头置顶

在开发后台管理系统时&#xff0c;表格是最常用的一个组件&#xff0c;为了看数据方便&#xff0c;时常需要固定表头。 如果页面基本只有一个表格区域&#xff0c;我们可以根据屏幕的高度动态的计算出一个值&#xff0c;给表格设定一个固定高度&#xff0c;这样表头就可以固定…

Transformer实战——摘要生成

本文借助Huggingface Tranformer库完成一个摘要生成任务&#xff0c;参考自https://github.com/datawhalechina/learn-nlp-with-transformers/&#xff0c;在本文&#xff0c;将展示如何使用简单的加载数据集&#xff0c;同时针对相应的任务使用transformer中的Trainer接口对模…

司美格鲁肽在中国获批!深度解析报告附上

在中国&#xff0c;肥胖问题日益严重&#xff0c;但有效的治疗方法却相对匮乏。然而&#xff0c;这一现状随着国家药品监督管理局&#xff08;NMPA&#xff09;对诺和诺德公司研发的司美格鲁肽注射液&#xff08;商品名&#xff1a;诺和盈&#xff09;的批准而得到改变。6月25日…

hadoop离线与实时的电影推荐系统-计算机毕业设计源码10338

摘 要 随着互联网与移动互联网迅速普及&#xff0c;网络上的电影娱乐信息数量相当庞大&#xff0c;人们对获取感兴趣的电影娱乐信息的需求越来越大,个性化的离线与实时的电影推荐系统 成为一个热门。然而电影信息的表示相当复杂&#xff0c;己有的相似度计算方法与推荐算法都各…

文件管理器加载缓慢-禁用文件类型自动发现功能

文件管理器加载缓慢-禁用文件类型自动发现功能 右键“Shell”项&#xff0c;选择新建“字符串值” “FolderType”&#xff0c;数值为 NotSpecified。

Python数据分析-糖尿病数据集数据分析

一、研究背景介绍 糖尿病是美国最普遍的慢性病之一&#xff0c;每年影响数百万美国人&#xff0c;并对经济造成重大的经济负担。糖尿病是一种严重的慢性疾病&#xff0c;其中个体失去有效调节血液中葡萄糖水平的能力&#xff0c;并可能导致生活质量和预期寿命下降。。。。糖尿…

【网络安全学习】漏洞利用:-01- BurpSuite的基础设置使用

Burp Suite是一款集成了多种功能的Web应用渗透测试工具&#xff0c;可以帮助渗透测试人员对Web应用进行拦截、分析、修改、重放、扫描、爆破、模糊测试等操作&#xff0c;从而发现和利用Web应用中的漏洞。可以说Burp Suite是每个安全从业人员必须学会使用的安全渗透测试工具。 …

服务器硬件以及RAID配置

目录 一、RAID磁盘阵列原理&#xff08;嘎嘎重要&#xff09; 1、RAID的概述 2、常用的RAID 2.1、RAID 0 2.2、RAID 1 2.3、RAID 5 2.5、RAID 10 3、阵列卡介绍 二、建立软件RAID磁盘阵列 1、添加硬盘 2、使用fdisk分区&#xff0c;类型为fd 3、mdata命令使用参数 …

今日好料(中国农业银行研发中心DevOps规划与实践)

今日好料&#xff08;中国农业银行研发中心DevOps规划与实践&#xff09; 在数字化转型的背景下&#xff0c;企业面临着更加复杂和多变的市场环境&#xff0c;对IT系统的敏捷性和稳定性提出了更高的要求。作为金融行业的领军企业&#xff0c;中国农业银行在其研发中心推进DevO…

eXosip协议栈构造Info应答并发送

最近在开发GB28181视频监控平台&#xff0c;对于录像的暂停、倍速等控制是通过INFO消息完成的&#xff0c;但是eXosip协议栈没有明确说明该如何去构造INFO消息的应答。通过对源代码的解读&#xff0c;是使用eXosip_call_send_answer接口去构造&#xff0c;参考了一些博客&#…

AI大模型训练过程

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 大模型训练概述 AI大模型训练是指在海量数据中&#xff0c;对拥有数百万至数千万参数及深层次神经网络结构的模型进行训练的过程。这类大模型因其庞大的参数规模和复杂的网…

【云原生】深入理解Pod的使用进行管理

深入理解Pod 文章目录 深入理解Pod一、介绍Pod1.1、什么是Pod1.2、Pod的特点1.3、Pod的用途1.4、Pod网络1.5、Pod存储1.6、Pod的工作方式 二、创建Pod2.1、命令行创建Pod2.2、资源清单创建Pod2.2.1、镜像拉取策略2.2.2、Pod重启策略2.2.3、部署资源2.2.4、删除资源 三、静态Pod…

大厂面试经验分享,小白如何在面试中脱颖而出

前言 毕业季&#xff0c;对于每一位即将步入社会的学子来说&#xff0c;都是一个充满挑战和机遇的时刻。作为我的一位好朋友也是好学长&#xff0c;他刚刚在一家顶尖科技公司斩获了他梦寐以求的职位。他深知求职路上的艰辛&#xff0c;因此打算把自己的经验分享给大家&#xf…

项目实战系列三: 家居购项目 第六部分

文章目录 &#x1f308;Ajax检验注册名&#x1f308;Ajax添加购物车&#x1f308;上传与更新家居图片&#x1f308;作业布置&#x1f34d;会员登陆后不能访问后台管理&#x1f34d;解决图片冗余问题&#x1f34d;分页导航完善 &#x1f308;Ajax检验注册名 需求分析 注册会员时…