环形队列
假想的环 充分利用空间,当rear=4,下一步到位置0
元素进队,影响的是队尾的值
进队才能队满 rear+1 % 最大值 是否等于队头
上一节中关于队列存在一个问题,队列是一次性队列,其实也是数组只用了一次,无法再次往队列中添加数据,这是数组实现队列的bug,所以在这一节会解决这个bug,采用环形队列的形式解决。
环形队列的思路如下
front:表示队列的第一个元素的位置,front初始值默认为0
rear:表示队列的最后一个元素的后一个位置,rear初始值默认为0,因为需要空出一个空间作为“约定”
当队列满时,条件是(rear + 1) % maxSize == front
当队列为空,条件是rear = front
当这样分析后,队列中有效的数据个数为(rear + maxSize - front) % maxSize
数组实现环形队列是数据结构的第一个难度,首先需要声明数组实现环形队列的方法有很多,但是这种是我个人觉得比较好理解的一种,这里做一下总结:front指针表示队首,并且控制出队;rear指针表示队尾的后一个位置,并且表示入队;队列长度为L时,队列可以存储的有效数据为L-1,因为空出一个空间作为约定,并且这个空间在不断的变化。
这里解释一下上面这张图:初始化队列的时候,队列的空间为4,队首指针front=0,队尾指针rear=0;把10入队,入队的时候front不动,将rear后移,即rear=(rear+1)%maxsize;当rear等于front时,表示队列满了。出队的时候rear不动,front后移,即front = (front+1)%maxsize;
环形队列就可以将队列无限次使用。
二、环形队列的代码实现
这里总结一下,环形队列并不是在内存中是向一个手环一样存储的,实际上你使用数组实现,在内存中就是一个普通的数组,这个数组长度是固定的,但是通过两个指针front和rear,取余的方式将这个队列变成了环形队列,而不像上一节说的那样的一个一次性的队列,环形队列的有点更加多,比如可以充分利用元素空间,其次出队速度和入队速度都非常快。
使用取余的方式做环形队列是需要注意一点,就是如果队列的长度为5的话,那么队列最多可以存储4个元素,因为需要空出一个空间来作为取余的约定,这个用文字表达起来很麻烦,只要按照这篇文章首部的图片所示,自己在草稿纸上画一个这样的示意图,那么对于环形队列的理解就非常深刻了。
这里说一句题外话,环形队列是数据结构与算法中第一个难点,前面的稀疏数组和队列都是比较简单的,但是环形队列是比较难理解的,后面还有更加难的单向环形链表等等,要坚持下去,我也会坚持下去尽量用好理解的白话讲述数据结构与算法的。
------------------------------------------------------------------------------------------------------------------------------------
预留一个空间判断是否为满还是空 front为0
假设(0+3+0)%3 = 0 个有效数字
class CircleArray{
//编写一个类,用数组模拟
private int maxSize;//表示数组最大容量
private int front;//队列的第一个元素
private int rear;//指向队列的最后一个元素的后一个位置,因为要空一格位置
private int[] arr;//该数组用于存放数据 模拟队列
public CircleArray(int arrmaxSize){
maxSize = arrmaxSize;
arr = new int[maxSize];
}
public boolean isFull(){
return (rear+1)%maxSize == front;
}
public boolean isEmpty(){
return rear == front;
}
public void addQueue(int n){
if(isFull()){
System.out.println("已满");
return;
} //将rear后移 必须考虑取模防止越界
arr[rear]= n;
rear = (rear+1)%maxSize;
}
public int getQueue(){
if (isEmpty()) {
throw new RuntimeException("空");
}
//分析出front是指向队列的第一个元素
//1.先将front对应的值保留到一个临时变量
//2.将front后移
//3.将临时保存的变量返回
int value = arr[front];
//arr[front] = arr[front++];肯定会报数组越界
front = (front + 1 )%maxSize;
return value;
}
public void showQueue(){
if (isEmpty()) {
System.out.println("为空");
}
//思路:从front开始遍历 遍历多少个元素 3+4-1就是例子 当前队列的有效个数
for (int i = front; i < front+size(); i++) {
System.out.printf("arr[%d]=%d\n",i%maxSize,arr[i%maxSize]);//有可能超过数组大小
}
}
public int size(){
return (rear+maxSize-front)%maxSize;
}
public int showhead(){
if (isEmpty()) {
throw new RuntimeException("队列空的没有数据");
}
return arr[front];//本身就指向第一个元素
}
约定的空间为0 ,动态变化
再添加的话会加到a[3]的位置
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律