队列与循环队列
目录
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…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor
1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...
