点击上方 好好学java ,选择 星标 公众号

重磅资讯、干货,第一时间送达
今日推荐:iphone 也是办公神器,用了就知道了,不行送你一个试试个人原创+1博客:点击前往,查看更多
链接:https://segmentfault.com/a/1190000022046581

在正式进行循环队列学习之前,我们先来看看在顺序队列中删除队首元素出现的问题:

(1)设一个容量为capacity=8,size=5(a,b,c,d,e)的数组,左侧为队首、右侧为队尾。

file

(2)出队一个元素后,需整体往前移动一位

出队:

file

整体前移一位:

file

关于该种操作方式我们很容易得出时间复杂度为O(n)。

这时我们就想可不可以在出队元素后,整体元素不往前移,而是在数组中记下队首front是谁,同时队尾tail指向在下一次元素入队时的位置,这样当再有出队时只需要维护一下front的指向即可,而不需移动元素。就这样我们就有了循环队列的情况。

file

1.循环队列原理

(1)初始,数组整体为空时,队首front、队尾tail指向同一个位置(数组索引为0的地方)也即front==tail 时队列为空

file

(2)当往数组中添加元素后

file

(3)出队一个元素,front指向新的位置

file

(4)入队元素,tail叠加

file

(5)当tail不能再增加时,数组前面还有空余,此时循环队列就该出场了。

file

此时数组应该变为这样:

file

在往数组中添加一个元素:

file

这样数组就已经满了(tail+1==front 队列满),开始出发扩容操作。capacity中,浪费一个空间。

为了tail能返回到数组的前面位置,将队列满的表达式变为 (tail+1)%c==front这样数组就可以循环移动了。

2.循环队列代码实现

新建一个类LoopQueue并实现接口Queue。

2.1、接口Queue代码如下:

package Queue;public interface Queue<E> {//获取队列中元素个数int getSize();//队列中元素是否为空boolean isEmpty();//入队列void enqueue(E e);//出队列E dequeue();//获取队首元素E getFront();
}

2.2、LoopQueue相关代码:

package Queue;//循环队列
public class LoopQueue<E> implements Queue<E> {private E[] data;private int front, tail;private int size;//队列中元素个数//构造函数,传入队列的容量capacity构造函数public LoopQueue(int capacity) {data = (E[]) new Object[capacity + 1];//浪费与一个空间front = 0;tail = 0;size = 0;}//无参构造函数,默认队列的容量capacity=10
public LoopQueue() {this(10);
}//真正容量
public int getCapacity() {return data.length - 1;
}//队列是否为空
@Override
public boolean isEmpty() {return front == tail;
}//队列中元素个数
@Override
public int getSize() {return size;
}//入队列操作
@Override
public void enqueue(E e) {if ((tail + 1) % data.length == front) {//队列已满,需要扩容resize(getCapacity() * 2);}data[tail] = e;tail = (tail + 1) % data.length;size++;
}//出队操作@Override
public E dequeue() {if (isEmpty()) {throw new IllegalArgumentException("队列为空");}E ret = data[front];data[front] = null;//手动释放front = (front + 1) % data.length;size--;if (size == getCapacity() / 4 && getCapacity() / 2 != 0) {resize(getCapacity() / 2);}return ret;
}//获取队首元素
@Override
public E getFront() {if (isEmpty()) {throw new IllegalArgumentException("队列为空");}return data[front];
}//改变容量
private void resize(int newCapacity) {E[] newData = (E[]) new Object[newCapacity + 1];for (int i = 0; i < size; i++) {newData[i] = data[(front + i) % data.length];//循环数组防止越界}data = newData;front = 0;tail = size;
}@Override
public String toString() {StringBuilder res = new StringBuilder();res.append(String.format("Queue:size=%d, capacity=%d\n", size, getCapacity()));res.append("front [");for (int i = front; i != tail; i = (i + 1) % data.length) {res.append(data[i]);if ((i + 1) % data.length != tail) {res.append(",");}}res.append("] tail");return res.toString();}}

在关于LoopQueue类中需要注意的:

(1)第11行中的+1是capacity需要浪费一个空间,故在实例化是多加1

data = (E[]) new Object[capacity + 1];//浪费与一个空间

(2)地24行真正的容量是data.length-1,这是由于有一个空间是浪费的。

data.length - 1;

(3)关于入队中第46行tail值的说明

为了保证入队是循环操作,tail值的变化规律为

tail = (tail + 1) % data.length;

(4)关于82行的数据迁移操作,取余操作是为了防止循环数组时越界。

newData[i] = data[(front + i) % data.length];//循环数组防止越界

2.3、直接在LoopQueue中添加一个main函数进行测试,相关代码如下:

//测试用例
public static void main(String[] args) {LoopQueue<Integer> queue = new LoopQueue<Integer>();for (int i = 0; i < 10; i++) {queue.enqueue(i);System.out.println(queue);if(i%3==2){//每添加3个元素出队列一个queue.dequeue();System.out.println(queue);}}}

结果为:

file

3.循环队列时间复杂度

file

到此我们就实现了一个循环队列操作,解决了在顺序队列中出队时的时间复杂度为O(n)的情况,在循环队列中出队的时间复杂度为O(1)。

Java 循环队列原理与用法详解相关推荐

  1. JAVA循环与分支语句edu_Java分支结构和循环结构原理与用法详解

    本文实例讲述了Java分支结构和循环结构.分享给大家供大家参考,具体如下: 流程控制分类 顺序语句:从上到下按顺序依次执行 分支语句:根据条件不同,执行不同语句 循环语句:重复执行某些动作 单分支条件 ...

  2. java设计模式观察者模式吗_Java设计模式之观察者模式原理与用法详解

    Java设计模式之观察者模式原理与用法详解 本文实例讲述了Java设计模式之观察者模式原理与用法.分享给大家供大家参考,具体如下: 什么是观察者模式 可以这么理解: 观察者模式定义了一种一对多的依赖关 ...

  3. redis队列优先级java实现_Redis 实现队列原理的实例详解

    Redis 实现队列原理的实例详解 场景说明: ·用于处理比较耗时的请求,例如批量发送邮件,如果直接在网页触发执行发送,程序会出现超时 ·高并发场景,当某个时刻请求瞬间增加时,可以把请求写入到队列,后 ...

  4. 《Java基础——break与continue用法详解》

    Java基础--break与continue用法详解 一. break语句: 规则: 1. 仅用于循环语句和switch语句当中,用于跳出循环. 2. 当只有一层循环时,则直接跳出循环,不再进行下一轮 ...

  5. java 枚举类型enum的用法详解

    Java Enum原理 public enum Size{ SMALL, MEDIUM, LARGE, EXTRA_LARGE }; 实际上,这个声明定义的类型是一个类,它刚好有四个实例,在此尽量不要 ...

  6. python的编程模式-Python设计模式之状态模式原理与用法详解

    本文实例讲述了Python设计模式之状态模式原理与用法.分享给大家供大家参考,具体如下: 状态模式(State Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类 ...

  7. java string()函数_转载java String.split()函数的用法详解

    转载java String.split()函数的用法详解 如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!在java.lang包中有String.split()方法的原型是: p ...

  8. Java(enum)枚举用法详解

    转载自 Java(enum)枚举用法详解 本篇文章主要介绍了Java 枚举用法详解,枚举的好处:可以将常量组织起来,统一进行管理.有兴趣的可以一起来了解一下. 概念 enum的全称为 enumerat ...

  9. python字符串strip的作用_Python字符串函数strip()原理及用法详解

    Python字符串函数strip()原理及用法详解 strip:用于移除字符串头尾指定的字符(默认为空格)或字符序列.注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符. 语法:str.s ...

最新文章

  1. C++应用程序性能优化
  2. 【运营】产品经理必须了解的运营方法,让你的产品有产有销
  3. python help()函数(查看特定模块、关键词、函数等用法)
  4. java中 flush()方法
  5. 如何用淘宝助理上传宝贝装修模板
  6. 样条 开源_成年人在开源社区中是什么样的?
  7. java 保存 设置_java的保存按钮怎么设置?
  8. Tinyalsa之mixer_ctl_set_value(十)
  9. SPSS 简单线性回归(图文+数据集)【SPSS 025期】
  10. 查看Cglib生成的Class(字节码)文件
  11. python plt引用_先引用matplotlib.pyplot再引用tensorflow报错问题
  12. 斐讯盒子T1_【YYF固件】夏杰语音实用版刷机固件及教程分享
  13. 检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件失败,原因是出现以下错误: 8000401a 因为配置标识不正确,系统无法开
  14. 左对齐杨辉三角python_什么是左的错误?
  15. 开始写usb gadget驱动
  16. 古诗词与代码之间不得不说的二三事。
  17. qq邮件exchange服务器,解决Exchange邮件系统无法接收QQ邮件的问题
  18. 【单片机】自学单片机第01天|单片机简介、内部资源、最小系统
  19. 悼念512汶川大地震的同胞
  20. google mapView 用法

热门文章

  1. Google搜索引擎的十大应用
  2. stm32 GPIO模式
  3. 数据挖掘 —— 探索性数据分析
  4. java元婴期(30)----java进阶(springmvc(4)---参数绑定(下)springmvc校验异常处理)
  5. 简单的计数器程序_javaweb
  6. Kubernetes中Pod的生命周期
  7. 通俗理解checked Exception和unchecked Exception
  8. Git 工作区、暂存区和版本库
  9. ida pro 7.5 idapython学习
  10. (27)TLB番外篇——ShadowWalker