【10.2】队列-设计循环队列
一、题目
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k): 构造器,设置队列长度为 k 。Front: 从队首获取元素。如果队列为空,返回 -1 。Rear: 获取队尾元素。如果队列为空,返回 -1 。enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。isEmpty(): 检查循环队列是否为空。isFull(): 检查循环队列是否已满。
示例:
MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3 circularQueue.enQueue(1); // 返回 true circularQueue.enQueue(2); // 返回 true circularQueue.enQueue(3); // 返回 true circularQueue.enQueue(4); // 返回 false,队列已满 circularQueue.Rear(); // 返回 3 circularQueue.isFull(); // 返回 true circularQueue.deQueue(); // 返回 true circularQueue.enQueue(4); // 返回 true circularQueue.Rear(); // 返回 4
提示:
- 所有的值都在 0 至 1000 的范围内;
- 操作数将在 1 至 1000 的范围内;
- 请不要使用内置的队列库。
二、解题思路
2.1 数组实现
我们可以通过数组来模拟循环队列,利用数组的索引构建一个虚拟的环形结构。在循环队列中,设置两个指针:队尾 `rear` 和队首 `front`,队列的大小是固定的。结构如下图所示:

在循环队列中,当队列为空时,`front` 和 `rear` 相等,即 `front == rear`;而当队列的所有空间都被占满时,同样会出现 `front == rear` 的情况。为了区分这两种状态,我们规定队列的数组容量为 `capacity`,但循环队列最多只能存储 `capacity - 1` 个元素。当队列中只剩下一个空闲的存储单元时,就认为队列已满。因此,队列判空的条件是 `front == rear`,而判满的条件是 `front == (rear + 1) % capacity`。
对于一个固定大小的数组,只要知道队尾 `rear` 和队首 `front`,就可以计算出队列的当前长度: (rear - front + capacity) mod capacity
循环队列的主要属性如下:
**`elements`**:一个固定大小的数组,用于存储循环队列的元素。
**`capacity`**:循环队列的容量,即队列中最多可以容纳的元素数量。
**`front`**:队首元素在数组中的索引。
**`rear`**:队尾元素的下一个位置的索引。
循环队列的接口方法如下:
**`MyCircularQueue(int k)`**:初始化队列,数组的空间大小为 `k + 1`,并将 `front` 和 `rear` 初始化为 0。
**`enQueue(int value)`**:在队列的尾部插入一个元素,并将 `rear` 更新为 `(rear + 1) % capacity`。
**`deQueue()`**:从队首取出一个元素,并将 `front` 更新为 `(front + 1) % capacity`。
**`Front()`**:返回队首的元素,需要先检测队列是否为空。
**`Rear()`**:返回队尾的元素,需要先检测队列是否为空。
**`isEmpty()`**:检测队列是否为空,只需判断 `rear` 是否等于 `front`。
**`isFull()`**:检测队列是否已满,只需判断 `front` 是否等于 `(rear + 1) % capacity`。
通过这种方式,循环队列能够高效地利用数组空间,同时避免普通队列在空间利用上的不足。
#include <iostream>
#include <vector>
using namespace std;class MyCircularQueue {
private:int front; // 队首指针int rear; // 队尾指针int capacity; // 队列容量vector<int> elements; // 用于存储队列元素的数组public:// 构造函数,初始化队列MyCircularQueue(int k) {this->capacity = k + 1; // 容量为 k + 1,多分配一个空间用于区分空和满状态this->elements = vector<int>(capacity); // 初始化数组rear = front = 0; // 初始化队首和队尾指针}// 向循环队列插入一个元素bool enQueue(int value) {if (isFull()) {return false; // 队列已满,插入失败}elements[rear] = value; // 将元素插入队尾rear = (rear + 1) % capacity; // 更新队尾指针(循环)return true;}// 从循环队列中删除一个元素bool deQueue() {if (isEmpty()) {return false; // 队列为空,删除失败}front = (front + 1) % capacity; // 更新队首指针(循环)return true;}// 获取队首元素int Front() {if (isEmpty()) {return -1; // 队列为空,返回 -1}return elements[front]; // 返回队首元素}// 获取队尾元素int Rear() {if (isEmpty()) {return -1; // 队列为空,返回 -1}return elements[(rear - 1 + capacity) % capacity]; // 返回队尾元素(处理循环情况)}// 检查队列是否为空bool isEmpty() {return rear == front; // 队首和队尾指针相等时,队列为空}// 检查队列是否已满bool isFull() {return ((rear + 1) % capacity) == front; // 队尾的下一个位置是队首时,队列已满}
};int main() {// 创建循环队列,容量为 3MyCircularQueue circularQueue(3);// 测试 enQueue 操作cout << "enQueue(1): " << circularQueue.enQueue(1) << endl; // 输出: 1 (true)cout << "enQueue(2): " << circularQueue.enQueue(2) << endl; // 输出: 1 (true)cout << "enQueue(3): " << circularQueue.enQueue(3) << endl; // 输出: 1 (true)cout << "enQueue(4): " << circularQueue.enQueue(4) << endl; // 输出: 0 (false,队列已满)// 测试 Rear 操作cout << "Rear(): " << circularQueue.Rear() << endl; // 输出: 3// 测试 isFull 操作cout << "isFull(): " << circularQueue.isFull() << endl; // 输出: 1 (true)// 测试 deQueue 操作cout << "deQueue(): " << circularQueue.deQueue() << endl; // 输出: 1 (true)// 测试 enQueue 操作cout << "enQueue(4): " << circularQueue.enQueue(4) << endl; // 输出: 1 (true)// 测试 Rear 操作cout << "Rear(): " << circularQueue.Rear() << endl; // 输出: 4// 测试 Front 操作cout << "Front(): " << circularQueue.Front() << endl; // 输出: 2// 测试 isEmpty 操作cout << "isEmpty(): " << circularQueue.isEmpty() << endl; // 输出: 0 (false)return 0;
}
复杂度分析
-
时间复杂度:初始化和每项操作的时间复杂度均为 O(1)。
-
空间复杂度:O(k),其中 k 为给定的队列元素数目。
2.2 链表实现
我们也可以使用链表来实现队列。与数组相比,链表实现队列更加灵活,因为链表可以在 O(1)时间复杂度内完成元素的插入和删除操作。具体来说,入队操作是将新元素插入到链表的尾部,而出队操作则是返回链表的头节点,并将头节点指向下一个节点。
循环队列的属性如下:
-
head:链表的头节点,表示队列的头部。 -
tail:链表的尾节点,表示队列的尾部。 -
capacity:队列的容量,即队列可以存储的最大元素数量。 -
size:队列当前存储的元素数量。
通过链表实现循环队列,可以避免数组实现中需要处理索引循环的问题,同时也能高效地完成队列的基本操作。
#include <iostream>
using namespace std;// 链表节点定义
struct ListNode {int val;ListNode *next;ListNode(int x) : val(x), next(nullptr) {}
};class MyCircularQueue {
private:ListNode *head; // 队首指针,指向链表的头节点ListNode *tail; // 队尾指针,指向链表的尾节点int capacity; // 队列的容量int size; // 队列当前的大小public:// 构造函数,初始化队列MyCircularQueue(int k) {this->capacity = k; // 设置队列容量this->size = 0; // 初始化队列大小为 0this->head = nullptr; // 初始化队首指针为空this->tail = nullptr; // 初始化队尾指针为空}// 向队列尾部插入一个元素bool enQueue(int value) {if (isFull()) {return false; // 队列已满,插入失败}ListNode *node = new ListNode(value); // 创建新节点if (!head) {head = tail = node; // 如果队列为空,新节点既是队首也是队尾} else {tail->next = node; // 将新节点链接到队尾tail = node; // 更新队尾指针}size++; // 队列大小加 1return true;}// 从队列头部删除一个元素bool deQueue() {if (isEmpty()) {return false; // 队列为空,删除失败}ListNode *node = head; // 保存队首节点head = head->next; // 更新队首指针size--; // 队列大小减 1delete node; // 释放队首节点的内存if (isEmpty()) {tail = nullptr; // 如果队列为空,更新队尾指针为空}return true;}// 获取队首元素int Front() {if (isEmpty()) {return -1; // 队列为空,返回 -1}return head->val; // 返回队首节点的值}// 获取队尾元素int Rear() {if (isEmpty()) {return -1; // 队列为空,返回 -1}return tail->val; // 返回队尾节点的值}// 检查队列是否为空bool isEmpty() {return size == 0; // 队列大小为 0 时为空}// 检查队列是否已满bool isFull() {return size == capacity; // 队列大小等于容量时为满}
};int main() {// 创建循环队列,容量为 3MyCircularQueue circularQueue(3);// 测试 enQueue 操作cout << "enQueue(1): " << circularQueue.enQueue(1) << endl; // 输出: 1 (true)cout << "enQueue(2): " << circularQueue.enQueue(2) << endl; // 输出: 1 (true)cout << "enQueue(3): " << circularQueue.enQueue(3) << endl; // 输出: 1 (true)cout << "enQueue(4): " << circularQueue.enQueue(4) << endl; // 输出: 0 (false,队列已满)// 测试 Rear 操作cout << "Rear(): " << circularQueue.Rear() << endl; // 输出: 3// 测试 isFull 操作cout << "isFull(): " << circularQueue.isFull() << endl; // 输出: 1 (true)// 测试 deQueue 操作cout << "deQueue(): " << circularQueue.deQueue() << endl; // 输出: 1 (true)// 测试 enQueue 操作cout << "enQueue(4): " << circularQueue.enQueue(4) << endl; // 输出: 1 (true)// 测试 Rear 操作cout << "Rear(): " << circularQueue.Rear() << endl; // 输出: 4// 测试 Front 操作cout << "Front(): " << circularQueue.Front() << endl; // 输出: 2// 测试 isEmpty 操作cout << "isEmpty(): " << circularQueue.isEmpty() << endl; // 输出: 0 (false)return 0;
}
复杂度分析
-
时间复杂度:初始化和每项操作的时间复杂度均为 O(1)。
-
空间复杂度:O(k),其中 k 为给定的队列元素数目。
相关文章:
【10.2】队列-设计循环队列
一、题目 设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普…...
多人-多agent协同可能会挑战维纳的反馈
在多人-多Agent协同系统中,维纳的经典反馈机制将面临新的挑战,而协同过程中的“算计”(策略性决策与协调)成为实现高效协作的核心。 1、非线性与动态性 维纳的反馈理论(尤其是在控制理论中)通常假设系统的动…...
JS 时间格式大全(含大量示例)
在 JS 中,处理时间和日期是常见的需求。无论是展示当前时间、格式化日期字符串,还是进行时间计算,JavaScript 都提供了丰富的 API 来满足这些需求。本文将详细介绍如何使用 JavaScript 生成各种时间格式,从基础到高级,…...
HarmonyOS简介:应用开发的机遇、挑战和趋势
问题 更多的智能设备并没有带来更好的全场景体验 连接步骤复杂数据难以互通生态无法共享能力难以协同 主要挑战 针对不同设备上的不同操作系统,重复开发,维护多套版本 多种语言栈,对人员技能要求高 多种开发框架,不同的编程…...
区间选点(贪心)
给定 NN 个闭区间 [ai,bi][ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。 输出选择的点的最小数量。 位于区间端点上的点也算作区间内。 输入格式 第一行包含整数 NN,表示区间数。 接下来 NN 行,…...
深度学习|表示学习|卷积神经网络|输出维度公式|15
如是我闻: 在卷积和池化操作中,计算输出维度的公式是关键,它们分别可以帮助我们计算卷积操作和池化操作后的输出大小。下面分别总结公式,并结合解释它们的意义: 1. 卷积操作的输出维度公式 当我们对输入图像进行卷积时…...
Edge-TTS在广电系统中的语音合成技术的创新应用
Edge-TTS在广电系统中的语音合成技术的创新应用 作者:本人是一名县级融媒体中心的工程师,多年来一直坚持学习、提升自己。喜欢Python编程、人工智能、网络安全等多领域的技术。 摘要 随着人工智能技术的快速发展,文字转语音(Te…...
2025课题推荐——USBL与DVL数据融合的实时定位系统
准确的定位技术是现代海洋探测、海洋工程和水下机器人操作的基础。超短基线(USBL)和多普勒速度计(DVL)是常用的水下定位技术,但单一技术难以应对复杂环境。因此,USBL与DVL的数据融合以构建实时定位系统&…...
RK3588平台开发系列讲解(ARM篇)ARM64底层中断处理
文章目录 一、异常级别二、异常分类2.1、同步异常2.2、异步异常三、中断向量表沉淀、分享、成长,让自己和他人都能有所收获!😄 一、异常级别 ARM64处理器确实定义了4个异常级别(Exception Levels, EL),分别是EL0到EL3。这些级别用于管理处理器的特权级别和权限,级别越高…...
MyBatis最佳实践:提升数据库交互效率的秘密武器
第一章:框架的概述: MyBatis 框架的概述: MyBatis 是一个优秀的基于 Java 的持久框架,内部对 JDBC 做了封装,使开发者只需要关注 SQL 语句,而不关注 JDBC 的代码,使开发变得更加的简单MyBatis 通…...
Three.js实战项目02:vue3+three.js实现汽车展厅项目
文章目录 实战项目02项目预览项目创建初始化项目模型加载与展厅灯光加载汽车模型设置灯光材质设置完整项目下载实战项目02 项目预览 完整项目效果: 项目创建 创建项目: pnpm create vue安装包: pnpm add three@0.153.0 pnpm add gsap初始化项目 修改App.js代码&#x…...
CPP-存储区域
CPP支持手动开辟和释放内存,所以对于内存的理解非常重要! 在C中,内存存储通常可以大致分为几个区域,这些区域根据存储的数据类型、生命周期和作用域来划分。这些区域主要包括: 代码区(Code Segment/Text S…...
1月27(信息差)
🌍喜大普奔,适用于 VS Code 的 GitHub Copilot 全新免费版本正式推出,GitHub 全球开发者突破1.5亿 🎄Kimi深夜炸场:满血版多模态o1级推理模型!OpenAI外全球首次!Jim Fan:同天两款国…...
开发环境搭建-3:配置 nodejs 开发环境 (fnm+ node + pnpm)
在 WSL 环境中配置:WSL2 (2.3.26.0) Oracle Linux 8.7 官方镜像 node 官网:https://nodejs.org/zh-cn/download 点击【下载】,选择想要的 node 版本、操作系统、node 版本管理器、npm包管理器 根据下面代码提示依次执行对应代码即可 基本概…...
深入理解Pytest中的Setup和Teardown
关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理,构建成功的基石 在自动化测试工作之前,你应该知道的10条建议 在自动化测试中,重要的不是工具 对于简单程序而言,使用 Pytest 运行测试直截了当。然而,当你…...
一个局域网通过NAT访问另一个地址重叠的局域网(IP方式访问)
正文共:1335 字 7 图,预估阅读时间:4 分钟 现在,我们已经可以通过调整两台设备的组合配置(地址重叠时,用户如何通过NAT访问对端IP网络?)或仅调整一台设备的配置(仅操作一…...
MongoDB中常用的几种高可用技术方案及优缺点
MongoDB 的高可用性方案主要依赖于其内置的 副本集 (Replica Set) 和 Sharding 机制。下面是一些常见的高可用性技术方案: 1. 副本集 (Replica Set) 副本集是 MongoDB 提供的主要高可用性解决方案,确保数据在多个节点之间的冗余存储和自动故障恢复。副…...
DeepSeek学术题目选择效果怎么样?
论文选题 一篇出色的论文背后,必定有一个“智慧的选题”在撑腰。选题足够好文章就能顺利登上高水平期刊;选题不行再精彩的写作也只能“当花瓶”。然而许多宝子们常常忽视这个环节,把大量时间花在写作上,选题时却像抓阄一样随便挑一…...
Lesson 119 A true story
Lesson 119 A true story 词汇 story n. 故事,传记,小说,楼层storey 搭配:tell a story 讲故事,说谎 true story 真实的故事 the second floor 二楼 例句:我猜他正在说谎。 I guess he…...
正反转电路梯形图
1、正转联锁控制。按下正转按钮SB1→梯形图程序中的正转触点X000闭合→线圈Y000得电→Y000自锁触点闭合,Y000联锁触点断开,Y0端子与COM端子间的内部硬触点闭合→Y000自锁触点闭合,使线圈Y000在X000触点断开后仍可得电。 Y000联锁触点断开&…...
Java并发学习:进程与线程的区别
进程的基本原理 一个进程是一个程序的一次启动和执行,是操作系统程序装入内存,给程序分配必要的系统资源,并且开始运行程序的指令。 同一个程序可以多次启动,对应多个进程,例如同一个浏览器打开多次。 一个进程由程…...
解锁罗技键盘新技能:轻松锁定功能键(罗技K580)
在使用罗技键盘的过程中,你是否曾因 F11、F12 功能键的默认设置与实际需求不符而感到困扰? 别担心,今天就为大家分享一个简单实用的小技巧 —— 锁定罗技键盘的 F11、F12 功能键,让你的操作更加得心应手! 通常情况下…...
分布式微服务系统架构第88集:kafka集群
使用集 群最大的好处是可以跨服务器进行负载均衡,再则就是可以使用复制功能来避免因单点故 障造成的数据丢失。在维护 Kafka 或底层系统时,使用集群可以确保为客户端提供高可用 性。 需要多少个broker 一个 Kafka 集群需要多少个 broker 取决于以下几个因…...
ESP32-S3模组上跑通esp32-camera(33)
接前一篇文章:ESP32-S3模组上跑通esp32-camera(32) 一、OV5640初始化 2. 相机初始化及图像传感器配置 上一回开始解析camera_probe函数的第8段即最后一段代码,本回继续解析该段代码。为了便于理解和回顾,再次贴出camera_probe函数源码,在components/esp32-camera/drive…...
一次端口监听正常,tcpdump无法监听到指定端口报文问题分析
tcpdump命令: sudo tcpdump -i ens2f0 port 6471 -XXnnvvv 下面是各个部分的详细解释: 1.tcpdump: 这是用于捕获和分析网络数据包的命令行工具。 2.-i ens2f0: 指定监听的网络接口。ens2f0 表示本地网卡),即计算机该指定网络接口捕…...
高可用集群故障之join
本文记录了在部署高可用的k8s集群时,遇到的一个故障及其解决方法。 集群环境 描述:三主三从,eth0为外网网卡,eth1为内网网卡,内网互通。 需求:eth0只负责访问外网,eth1作为集群间的通信。 主…...
uniapp版本升级
1.样式 登录进到首页,弹出更新提示框,且不可以关闭,侧边返回直接退出! 有关代码: <uv-popup ref"popupUpdate" round"8" :close-on-click-overlay"false"><view style"…...
Ubuntu 20.04 x64下 编译安装ffmpeg
试验的ffmpeg版本 4.1.3 本文使用的config命令 ./configure --prefixhost --enable-shared --disable-static --disable-doc --enable-postproc --enable-gpl --enable-swscale --enable-nonfree --enable-libfdk-aac --enable-decoderh264 --enable-libx265 --enable-libx…...
【Web开发】一步一步详细分析使用Bolt.new生成的简单的VUE项目
https://bolt.new/ 这是一个bolt.new生成的Vue小项目,让我们来一步一步了解其架构,学习Vue开发,并美化它。 框架: Vue 3: 用于构建用户界面。 TypeScript: 提供类型安全和更好的开发体验。 Vite: 用于快速构建和开发 主界面如下:…...
SpringBoot源码解析(八):Bean工厂接口体系
SpringBoot源码系列文章 SpringBoot源码解析(一):SpringApplication构造方法 SpringBoot源码解析(二):引导上下文DefaultBootstrapContext SpringBoot源码解析(三):启动开始阶段 SpringBoot源码解析(四):解析应用参数args Sp…...
