如何通过java优雅的实现一个环形数组?下面提供2种实现方式

  • SimpleCircularArray是环形数组简单实现
  • CircularArrayHolder代码实现参考的是com.netflix.hystrix.utilHystrixRollingNumber

实现方式一、SimpleCircularArray

bucket

/*** 桶** @author wenpanfeng 2022/07/30 11:17*/
public class Bucket {/*** 桶名称*/String name;public Bucket() {}public Bucket(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

SimpleCircularArray

/*** 简单的环形数组实现,非线程安全,若需保证线程安全只需要在使用时对addLast和clear方法加锁即可** @author wenpanfeng 2022/07/30 13:34*/
public class SimpleCircularArray implements Iterable<Bucket> {/*** 环形数组,数组里是一个个的桶,桶内需要放什么数据可自己决定*/private final AtomicReferenceArray<Bucket> circularArray;/*** 头指针*/private int head;/*** 尾指针*/private int tail;/*** 当前数组内元素的个数*/private int size;/*** 环形数组容量*/private final int capacity;public SimpleCircularArray(int capacity) {circularArray = new AtomicReferenceArray<>(capacity);head = 0;tail = 0;this.capacity = capacity;}public SimpleCircularArray(AtomicReferenceArray<Bucket> circularArray) {this.circularArray = circularArray;head = 0;tail = 0;capacity = circularArray.length();}public void addLast(Bucket bucket) {// 已经到达最后一个if (size == capacity) {if (head == capacity - 1) {head = 0;} else {head = head + 1;}if (tail == capacity) {circularArray.set(0, bucket);tail = 1;} else {circularArray.set(tail, bucket);tail = tail + 1;}} else {// 环形数组中元素个数还未达到capacity,则只移动tailcircularArray.set(tail, bucket);tail = tail + 1;size++;}}/*** 清除环形数组*/public void clear() {size = 0;head = 0;tail = 0;}/*** 在内部数组的副本上返回一个迭代器,以便迭代器不会因同时添加删除的存储桶而失败。*/@Overridepublic Iterator<Bucket> iterator() {// 获取环形数组里的所有元素,这里获取到的是环形数组里的元素的副本return Collections.unmodifiableList(Arrays.asList(getArray())).iterator();}/*** 获取环形数组中所有元素*/protected Bucket[] getArray() {List<Bucket> array = new ArrayList<>();// 依次获取环形数组内部所有元素并加入到新的listfor (int i = 0; i < size; i++) {array.add(circularArray.get(convert(i)));}return array.toArray(new Bucket[0]);}/*** convert() 方法采用逻辑索引(好像 head 始终为 0)并计算 elementData 内的索引*/private int convert(int index) {return (index + head) % (capacity);}}

实现方式二、CircularArrayHolder

/*** 环形数组管理器,通过该holder来方便的操作环形数组** @author wenpanfeng 2022/07/30 11:12*/
public class CircularArrayHolder implements Iterable<Bucket> {/*** 持有一个环形数组的引用,以便于可以通过该引用方便的访问环形数组*/private final AtomicReference<CircularArray> circularArray;/*** 固定值,一旦创建就不会改变, 预留一个空间,作为后续向环形数组增减和删除的支持,* 长度始终为:桶的数量 + 1,比如:如果环形数组里有10个桶,那么该值就是11* <p>*/private final int dataLength;/*** 桶的数量*/private final int numBuckets;/*** 构造函数*/public CircularArrayHolder(int size) {// + 1 as extra room for the add/remove;AtomicReferenceArray<Bucket> buckets = new AtomicReferenceArray<>(size + 1);// state持有该环形数组的引用circularArray = new AtomicReference<>(new CircularArray(buckets, 0, 0));dataLength = buckets.length();numBuckets = size;}/*** 清除环形数组里的所有元素(线程安全)*/public void clear() {while (true) {// 获取到环形数组的引用CircularArray currentCircularArray = circularArray.get();// 调用环形数组的clear方法,此时会返回环形数组新的引用CircularArray newCircularArray = currentCircularArray.clear();// 使用新的引用替换旧的引用if (circularArray.compareAndSet(currentCircularArray, newCircularArray)) {// 如果cas替换成功则退出,不然则进行下一次尝试return;}}}/*** 在内部数组的副本上返回一个迭代器,以便迭代器不会因同时添加删除的存储桶而失败。*/@Overridepublic Iterator<Bucket> iterator() {// 获取环形数组里的所有元素,这里获取到的是环形数组里的元素的副本return Collections.unmodifiableList(Arrays.asList(getArray())).iterator();}/*** 往环形数组尾部添加一个bucket(非线程安全)*/public void addLast(Bucket bucket) {// 获取到环形数组的引用CircularArray currentCircularArray = circularArray.get();// 将元素添加到环形数组里,添加成功后会返回一个新的环形数组的引用CircularArray newCircularArray = currentCircularArray.addBucket(bucket);// 将circularArray重新指向最新的环形数组circularArray.compareAndSet(currentCircularArray, newCircularArray);}/*** 获取环形数组最后一个元素*/public Bucket getLast() {return peekLast();}/*** 获取环形数组里的元素个数*/public int size() {// 大小也可以每次计算为: return (tail + data.length() - head) % data.length();return circularArray.get().size;}/*** 获取环形数组最后一个元素*/public Bucket peekLast() {return circularArray.get().tail();}/*** 获取环形数组中所有的元素*/private Bucket[] getArray() {return circularArray.get().getArray();}/*** 私有内部类,不允许外部直接访问(环形数组实现类,适用于写多读少的场景)*/private class CircularArray {/*** 环形数组,数组里是一个个的桶,桶内需要放什么数据可自己决定*/protected final AtomicReferenceArray<Bucket> data;/*** 环形数组的大小(也就是环形数组中现有元素的个数)*/protected final int size;/*** 数组头节点下标索引*/protected final int tail;/*** 数组尾节点下标索引*/protected final int head;/*** 构造方法*/public CircularArray(AtomicReferenceArray<Bucket> data, int head, int tail) {this.data = data;this.head = head;this.tail = tail;// 计算sizeif (head == 0 && tail == 0) {size = 0;} else {size = (tail + dataLength - head) % dataLength;}}/*** 获取环形数组尾部元素*/public Bucket tail() {// 桶内还没有元素时,返回nullif (size == 0) {return null;} else {// we want to get the last item, so size()-1return data.get(convert(size - 1));}}/*** convert() 方法采用逻辑索引(好像 head 始终为 0)并计算 elementData 内的索引*/private int convert(int index) {return (index + head) % dataLength;}/*** 获取环形数组中所有的元素*/protected Bucket[] getArray() {List<Bucket> array = new ArrayList<>();// 依次获取环形数组内部所有元素并加入到新的listfor (int i = 0; i < size; i++) {array.add(data.get(convert(i)));}return array.toArray(new Bucket[0]);}/*** 增加一个元素到环形数组尾部*/private CircularArray incrementTail() {// 如果已经到达环形数组最大长度,则头尾指针一起移动if (size == numBuckets) {return new CircularArray(data, (head + 1) % dataLength, (tail + 1) % dataLength);} else {// 如果还没有到达环形数组最大容量,则increment only tailreturn new CircularArray(data, head, (tail + 1) % dataLength);}}/*** 清除环形数组,其实也就是新建一个CircularArray然后将头尾指针都指向0位置** @return CircularArray* @author wenpanfeng 2022/7/28 21:31*/public CircularArray clear() {return new CircularArray(new AtomicReferenceArray<>(dataLength), 0, 0);}/*** 添加一个桶到环形数组里*/public CircularArray addBucket(Bucket bucket) {// 设置尾结点位置的值为bucketdata.set(tail, bucket);// 尾部移动一个return incrementTail();}}}

测试

public class Main {public static void main(String[] args) {System.out.println("=============================测试CircularArrayHolder=============================");CircularArrayHolder holder = new CircularArrayHolder(10);for (int i = 0; i < 20; i++) {holder.addLast(new Bucket(String.valueOf(i)));}for (Bucket next : holder) {System.out.println(next.getName());}holder.clear();System.out.println("==================================================");for (Bucket next : holder) {System.out.println(next.getName());}System.out.println("=============================测试SimpleCircularArray=============================");SimpleCircularArray simpleCircularArray = new SimpleCircularArray(10);for (int i = 0; i < 10; i++) {simpleCircularArray.addLast(new Bucket(String.valueOf(i)));}for (Bucket bucket : simpleCircularArray) {System.out.println(bucket.getName());}simpleCircularArray.clear();System.out.println("======================================");for (int i = 0; i < 5; i++) {simpleCircularArray.addLast(new Bucket(String.valueOf(i)));}for (Bucket bucket : simpleCircularArray) {System.out.println(bucket.getName());}simpleCircularArray.clear();System.out.println("======================================");for (int i = 0; i < 3; i++) {simpleCircularArray.addLast(new Bucket(String.valueOf(i)));}for (Bucket bucket : simpleCircularArray) {System.out.println(bucket.getName());}simpleCircularArray.clear();System.out.println("======================================");for (int i = 0; i < 500; i++) {simpleCircularArray.addLast(new Bucket(String.valueOf(i)));}for (Bucket bucket : simpleCircularArray) {System.out.println(bucket.getName());}}
}

java实现环形数组相关推荐

  1. Java实现 LeetCode 457 环形数组循环

    457. 环形数组循环 给定一个含有正整数和负整数的环形数组 nums. 如果某个索引中的数 k 为正数,则向前移动 k 个索引.相反,如果是负数 (-k),则向后移动 k 个索引.因为数组是环形的, ...

  2. 扫盲!Java可变长数组,看这篇就对了!

    来自:ImportNew/覃佑桦 | 责编:乐乐 链接:tutorials.jenkov.com/java-performance/resizable-array.html 有时我们希望将把数据保存在 ...

  3. 环形数组求最大子数组之和

    环形数组求最大子数组之和: 实验要求: 随机产生一个整形数组,假设首尾相连为环形,求其相连的字数组的和,并输出子数组的元素. 设计思路: 因为是环形,所以要考虑自设的头尾的情况,在此分为两大类考虑,一 ...

  4. 《团队项目开发之三对一维环形数组的求解》

    <团队项目开发之三对一维环形数组的求解> 设计思想:通过把数组的长度扩大为原来的一倍,相当于新数组是由对原来的数组重复了一遍后而组成的,这样保证了数组以环状的形式,按照数组中每个数字的位序 ...

  5. JAVA学习笔记--数组初始化

    JAVA中,数组只是相同类型的.用一个标识符名称封装到一起的一个对象序列或基本类型数据序列.数组通过方括号下标操作符[]来定义和使用,要定义一个数组只需在类型名后面加上一个方括号即可,如: int[] ...

  6. java的byte php_java_浅谈java的byte数组的不同写法,(由于篇幅原因阐述的不够详 - phpStudy...

    浅谈java的byte数组的不同写法 (由于篇幅原因阐述的不够详细科学,不喜勿喷). 经常看到java中对byte数组的不同定义,粗略整理的一下: 一个字节(byte)=8位(bit),"b ...

  7. Java学习_day007:数组与方法

    一.数组 数组的复制 int[]a={10,20,30,40,50}; int[]b=new int[6]; //b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4 ...

  8. [算法] 求环形数组中和值最大子段

    对于非环形数组,求解和值最大子段的方法见之前一遍文章: 对于环形数组,需要考虑最大和值子段越过首尾边界的情况,解决方法比较简单,即将数组处理两遍: 需要注意子段长度不可以超过整个数组长度: 1 #! ...

  9. java 复制一个数组_浅谈Java中复制数组的方式

    在Java里面,可以用复制语句"A=B"给基本类型的数据传递值,但是如果A,B是两个同类型的数组,复制就相当于将一个数组变量的引用传递给另一个数组:如果一个数组发生改变,那么引用同 ...

最新文章

  1. UVa11300 - Spreading the Wealth
  2. 武汉大专计算机专业分数线,武汉高考分数线最低的大专,2021年武汉大专最低分数线是多少...
  3. 未老先呆,这锅熬夜真的要背:生物钟影响阿尔茨海默症的机制被发现
  4. synamic-datasource-spring-boot-starter实现动态数据源Mysql和Sqlserver
  5. Excel表格内容导出到页面
  6. android 底部滑动效果怎么做,Android实现简单底部导航栏 Android仿微信滑动切换效果...
  7. 51Nod-1179 最大的最大公约数【暴力】
  8. 2017计算机绘图试题及答案,2017年度__电大(精编新版)计算机绘图期末复习试题及答案参考小抄.doc...
  9. 搭建SpringMVC
  10. 一文总结数据科学家常用的Python库(上)
  11. 游戏服务器开发技术栈
  12. 雷达图像与电子海图叠加坐标变化优化方法
  13. Oracle Coherence中文教程三:配置
  14. matlab人口数据,matlab中国人口
  15. 计算语言学之句法理论(1)
  16. 计蒜客 - 蒜头君的任务
  17. 【前端CSS】CSS的选择器属性详细介绍
  18. 2022艾灸展,艾健康展,艾棒展,山东艾制品展,艾绒纺织展
  19. Android 蓝牙开发(扫描设备、绑定、解绑)Kotlin版
  20. 飞漫魏永明:从MiniGUI看嵌入式十年得与失

热门文章

  1. Maven插件wro4j-maven-plugin压缩、合并js、css详解
  2. 基于unity制作的AR视频播放
  3. 杨幂换脸不算啥,AI还能造出“并不存在”的美食图、假简历
  4. 颜色空间探究:RGB、HSV和HSL
  5. 预训练模型最新综述:过去、现在和未来
  6. learnopengl网站学习2.着色器.txt
  7. Docker File
  8. 追觅慧目F9、戴森360 Heurist、石头T7三款扫地机器人哪个更好
  9. 快速获取系统字体列表
  10. day21-pdf作业