队列与循环队列
目录
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 4typedef 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 4typedef 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 4typedef 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;
}
相关文章:
队列与循环队列
目录 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 销毁队列 …...
python基础问题记录
文章目录 前言一、python中类的注意点二、模块与包1. 模块2. 包 总结 前言 本专栏主要记录python中一些语法问题。 一、python中类的注意点 类属性:在类中定义的属性 在类中直接写明的变量是类属性,属于公共属性。 访问:类属性可以通过类或…...
Qt之饼图(Pie Graph)
[TOC](Qt之饼图(Pie Graph)) 饼图名为Pie Graph,用于显示一个数据系列中各项的大小与各项总和的比例。本文基于QtCharts实现饼图的显示。 1.实现过程 1.1环境配置 (1)首先想要使用QtCharts模块,需要在安装qt时选择勾选安装QtCha…...
Java项目Git提交规范
在Java项目中,遵循良好的Git提交规范有助于提高代码的可维护性、可读性和团队协作效率。以下是一些常见的Git提交规范建议: 文章目录 提交信息格式提交信息示例提交频率分支管理代码审查工具和自动化提交前检查清单 提交信息格式 提交类型:使…...
flink-触发器Trigger和移除器Evictor
窗口原理与机制 图片链接:https://blog.csdn.net/qq_35590459/article/details/132177154 数据流进入算子前,被提交给WindowAssigner,决定元素被放到哪个或哪些窗口,同时可能会创建新窗口或者合并旧的窗口。每一个窗口都拥有一个…...
【力扣 28】找出字符串中第一个匹配项的下标 C++题解(字符串匹配)
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。 示例 1: 输入:haystack “s…...
软件构造 | Design Patterns for Reuse and Maintainability
Design Patterns for Reuse and Maintainability (面向可复用性和可维护性的设计模式) Open-Closed Principle (OCP) ——对扩展的开放,对修改已有代码的封 Why reusable design patterns A design… …enables flexibility to change …...
Python数据分析-股票分析和可视化(深证指数)
一、内容简介 股市指数作为衡量股市整体表现的重要工具,不仅反映了市场的即时状态,也提供了经济健康状况的关键信号。在全球经济体系中,股市指数被广泛用于预测经济活动,评估投资环境,以及制定财政和货币政策。在中国…...
Linux如何安装openjdk1.8
文章目录 Centosyum安装jdk和JRE配置全局环境变量验证ubuntu使用APT(适用于Ubuntu 16.04及以上版本)使用PPA(可选,适用于需要特定版本或旧版Ubuntu)Centos yum安装jdk和JRE yum install java-1.8.0-openjdk-devel.x86_64 安装后的目录 配置全局环境变量 vim /etc/pr…...
【LLVM】LTO学习
看这篇文章,文中的代码都是错的,给出的命令行也是错的。 真不如参考文献中也是华为的外国员工写的PPT。 但是,上述的文件中的指令也存在报错,还是官方文档看着舒服。...
事务的特性-原子性(Atomicity)、一致性(Consistency)、隔离性(Asolation)、持久性(Durability)
一、引言 1、数据库管理系统DBMS为保证定义的事务是一个逻辑工作单元,达到引入事务的目的,实现的事务机制要保证事务具有原子性、一致性、隔离性和持久性,事务的这四个特性也统称为事务的ACID特性 2、当事务保持了ACID特性,才能…...
redis哨兵模式(Redis Sentinel)
哨兵模式的背景 当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式。 为了解决单点故障和提高系统的可用性,需要一种自动化的监…...
【牛客】牛客小白月赛97 题解 A - E
文章目录 A - 三角形B - 好数组C - 前缀平方和序列D - 走一个大整数迷宫E - 前缀和前缀最大值 A - 三角形 map存一下每个数出现了多少次,再遍历map #include <bits/stdc.h>using namespace std;#define int long long using i64 long long;typedef pair<…...
Spring Boot中泛型参数的灵活运用:最佳实践与性能优化
泛型是Java中一种强大的特性,它提供了编写通用代码的能力,使得代码更加灵活和可复用。在Spring Boot应用程序中,泛型参数的灵活运用可以带来诸多好处,包括增强代码的可读性、提高系统的健壮性以及优化系统的性能。本文将深入探讨在…...
MySQL建表时的注意事项
以下是我对MySQL建表时的注意事项。其实,建表事项有很多,我的总结如下: 1 存储引擎的选择,一般做开发,都是要支持事务的,所以选择InnoDB 2 对字段类型的选择: 对于日期类型如果要记录时分…...
Advanced RAG 09:『提示词压缩』技术综述
编者按: 如何最大限度地发挥 LLMs 的强大能力,同时还能控制其推理成本?这是当前业界研究的一个热点课题。 针对这一问题,本期精心选取了一篇关于"提示词压缩"(Prompt Compression)技术的综述文章。正如作者所说…...
(13)DroneCAN 适配器节点(二)
文章目录 前言 2 固件 2.1 基于F103 2.2 基于F303 2.3 基于F431 3 ArduPilot固件DroneCAN设置 3.1 f303-通用设置示例 4 DroneCAN适配器节点 前言 这些节点允许现有的 ArduPilot 支持的外围设备作为 DroneCAN 或 MSP 设备适应 CAN 总线。这也允许扩展自动驾驶仪硬件的…...
摸鱼大数据——Spark基础——Spark环境安装——Spark Local[*]搭建
一、虚拟机配置 查看每一台的虚拟机的IP地址和网关地址 查看路径: cat /etc/sysconfig/network-scripts/ifcfg-ens33 2.修改 VMware的网络地址: 使用VMnet8 3.修改windows的对应VMware的网卡地址 4.通过finalshell 或者其他的shell连接工具即可连接使用即可, 连接后, 测试一…...
函数内部结构分层浅析(从MVC分层架构联想)
函数内部结构分层浅析(从MVC分层架构联想) 分层架构:一种将软件代码按不同功能进行划分的架构模式。 优点包括: 可维护性:各层职责明确,易于单独修改维护。 可扩展性:方便添加或修改某一层,不…...
【three.js案例二】时空隧道
import * as THREE from ./build/three.module.js // 引入轨道控制器扩展库OrbitControls.js import { OrbitControls } from three/addons/controls/OrbitControls.js; // 引入dat.gui.js的一个类GUI import { GUI } from three/addons/libs/lil-gui.module.min.js;// 场景 co…...
Shell脚本加固实战:用shellguard提升脚本健壮性与安全性
1. 项目概述:一个为Shell脚本穿上“防弹衣”的守护者 在运维开发、自动化部署乃至日常的系统管理工作中,Shell脚本是我们最忠实、最高效的伙伴。从简单的日志清理到复杂的CI/CD流水线,Shell脚本无处不在。然而,脚本的安全性、健壮…...
Grad-CAM实战:用热力图透视神经网络的决策焦点
1. Grad-CAM技术初探:为什么我们需要热力图? 当你训练了一个图像分类模型,准确率高达95%,但你真的了解它是如何做出判断的吗?我曾在项目中遇到过这样的尴尬:模型把一只坐在草地上的哈士奇误判为"狼&qu…...
AI全栈开发实战:基于Cursor的智能代码生成与架构设计
1. 项目概述:当AI代码助手遇上全栈开发最近在GitHub上看到一个挺有意思的项目,叫“Cursor-FullStack-AI-App”。光看名字,你大概能猜到它和Cursor这个AI代码编辑器有关,并且涉及全栈应用开发。但它的价值远不止于此。作为一个在前…...
从零解析开源API网关fiGate:架构设计与生产实践
1. 项目概述:从零解析一个开源API网关最近在梳理团队内部微服务治理方案时,我又重新审视了市面上各类API网关的实现。除了大家耳熟能详的Kong、APISIX、Tyk这些“明星产品”,其实在GitHub的海洋里,还藏着不少设计精巧、思路独特的…...
C++中的封装、继承、多态理解
封装(encapsulation):就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成”类”,其中数据和函数都是类的成员。封装的目的是增强安全性和简化编程&…...
Midjourney极简艺术风格实战手册(2024V6.2最新适配版):含17个已验证失效词黑名单与8组高通过率--sref权重组合
更多请点击: https://intelliparadigm.com 第一章:Midjourney极简艺术风格的核心定义与美学边界 极简艺术风格在 Midjourney 中并非单纯减少元素,而是通过语义压缩、形式提纯与负空间策略构建高度凝练的视觉语言。其核心在于以最少的视觉单元…...
SingleFile CLI架构解析:高性能网页批量保存解决方案与实战指南
SingleFile CLI架构解析:高性能网页批量保存解决方案与实战指南 【免费下载链接】SingleFile Web Extension for saving a faithful copy of a complete web page in a single HTML file 项目地址: https://gitcode.com/gh_mirrors/si/SingleFile SingleFile…...
基于CircuitPython与ESP32-S3的智能LED矩阵闹钟项目全解析
1. 项目概述与核心思路几年前,当我第一次接触ESP32和MicroPython时,就被其“用Python玩硬件”的理念深深吸引。但说实话,早期的MicroPython在库支持和开发体验上,对新手并不算太友好。直到Adafruit推出了CircuitPython,…...
UPS Ground运输时间估算:从纽约10013到全美各区域的实操指南
1. 物流时间估算的核心价值与挑战在电商和供应链的世界里,时间就是金钱,而运输时间则是连接承诺与现实的桥梁。无论是作为卖家管理客户预期,还是作为买家规划项目进度,一个相对准确的运输时间预估都至关重要。UPS Ground作为美国境…...
Spoolman:终极3D打印线轴管理解决方案,让您的打印工作更高效 [特殊字符]
Spoolman:终极3D打印线轴管理解决方案,让您的打印工作更高效 🚀 【免费下载链接】Spoolman Keep track of your inventory of 3D-printer filament spools. 项目地址: https://gitcode.com/gh_mirrors/sp/Spoolman Spoolman是一个强大…...
