动态循环数组(ArrayList优化)
测试结果分析
动态数组有一个最大的弊端就是浪费内存空间,这个无法避免。
还有一个弊端就是添加删除都需要移动数组元素,最坏情况下要从头移动到尾,也就是n次,致使时间复杂度为O(n) 。
下面这个例子就解决了这个问题,通过判断索引位置,移动元素少的一端,可以至少节约一半的时间。
这个对外使用是无感的,只是内部逻辑实现不同而已。
初始化10,添加8个元素:
CircleArrayList{size=8, head=0, elementData=[1, 2, 3, 4, 5, 6, 7, 8]}
NewRealArrayList{size=8, head=0, elementData=[1, 2, 3, 4, 5, 6, 7, 8, null, null]}
删除第一个元素:
CircleArrayList{size=7, head=1, elementData=[2, 3, 4, 5, 6, 7, 8]}
NewRealArrayList{size=7, head=1, elementData=[null, 2, 3, 4, 5, 6, 7, 8, null, null]}
删除最后一个元素(此时元素有7个索引是6):
CircleArrayList{size=6, head=1, elementData=[2, 3, 4, 5, 6, 7]}
NewRealArrayList{size=6, head=1, elementData=[null, 2, 3, 4, 5, 6, 7, null, null, null]}
结尾添加一个元素:
CircleArrayList{size=7, head=1, elementData=[2, 3, 4, 5, 6, 7, 9]}
NewRealArrayList{size=7, head=1, elementData=[null, 2, 3, 4, 5, 6, 7, 9, null, null]}
删除索引为1的元素(测试删除前半的元素):
CircleArrayList{size=6, head=2, elementData=[2, 4, 5, 6, 7, 9]}
NewRealArrayList{size=6, head=2, elementData=[null, null, 2, 4, 5, 6, 7, 9, null, null]}
删除索引为4的元素(测试删除前半的元素):
CircleArrayList{size=5, head=2, elementData=[2, 4, 5, 6, 9]}
NewRealArrayList{size=5, head=2, elementData=[null, null, 2, 4, 5, 6, 9, null, null, null]}
删除索引为2的元素(测试删除中间的元素):
CircleArrayList{size=4, head=2, elementData=[2, 4, 6, 9]}
NewRealArrayList{size=4, head=2, elementData=[null, null, 2, 4, 6, 9, null, null, null, null]}
在索引为1的位置添加元素(测试添加前半的元素):
CircleArrayList{size=5, head=1, elementData=[2, 331, 4, 6, 9]}
NewRealArrayList{size=5, head=1, elementData=[null, 2, 331, 4, 6, 9, null, null, null, null]}
在索引为3的位置添加元素(测试添加后半的元素):
CircleArrayList{size=6, head=1, elementData=[2, 331, 4, 551, 6, 9]}
NewRealArrayList{size=6, head=1, elementData=[null, 2, 331, 4, 551, 6, 9, null, null, null]}
结尾添加一个元素:
CircleArrayList{size=7, head=1, elementData=[2, 331, 4, 551, 6, 9, 10]}
NewRealArrayList{size=7, head=1, elementData=[null, 2, 331, 4, 551, 6, 9, 10, null, null]}
在索引为3的位置添加元素(测试添加中间的元素):
CircleArrayList{size=8, head=1, elementData=[2, 331, 4, 550, 551, 6, 9, 10]}
NewRealArrayList{size=8, head=1, elementData=[null, 2, 331, 4, 550, 551, 6, 9, 10, null]}
在索引为5的位置添加两个元素(测试绕环):
CircleArrayList{size=10, head=1, elementData=[2, 331, 4, 550, 551, 552, 553, 6, 9, 10]}
NewRealArrayList{size=10, head=1, elementData=[10, 2, 331, 4, 550, 551, 552, 553, 6, 9]}
删除刚才添加的两个元素(测试删除对象):
CircleArrayList{size=8, head=1, elementData=[2, 331, 4, 550, 551, 6, 9, 10]}
NewRealArrayList{size=8, head=1, elementData=[null, 2, 331, 4, 550, 551, 6, 9, 10, null]}
在索引为2的位置添加两个元素(测试前绕环):
CircleArrayList{size=10, head=-1, elementData=[2, 331, 332, 333, 4, 550, 551, 6, 9, 10]}
NewRealArrayList{size=10, head=-1, elementData=[331, 332, 333, 4, 550, 551, 6, 9, 10, 2]}
在索引为5的位置添加一个元素(测试扩容):
CircleArrayList{size=11, head=0, elementData=[2, 331, 332, 333, 4, 441, 550, 551, 6, 9, 10]}
NewRealArrayList{size=11, head=0, elementData=[2, 331, 332, 333, 4, 441, 550, 551, 6, 9, 10, null, null, null, null]}
源代码
package datastruct.linearlist;import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;/*** 循环数组* 核心在于索引* 提升效率* 前半添加前半删除扩容缩容处理head*/
public class HtqCircleArrayList<E> {private int head;private int size;private Object[] elementData;private int DEFAULT_CAPACITY = 10;private Object[] EMPTY_ELEMENTDATA = {};private int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;public HtqCircleArrayList() {elementData = EMPTY_ELEMENTDATA;}public HtqCircleArrayList(int initCapacity) {if (initCapacity<0){throw new IllegalArgumentException();}else if (initCapacity ==0){elementData = EMPTY_ELEMENTDATA;}else {elementData = new Object[initCapacity];}}private int realIndex(int index){return (index+head>=elementData.length)?(index+head-elementData.length):(index+head<0)?index+head+elementData.length:index+head;}//error no checkpublic void trimToSize(){if (size>=elementData.length) return;if (size==0){elementData = EMPTY_ELEMENTDATA;return;}Object[] objects = new Object[size];for (int i=0;i<size;i++){objects[i] = elementData[realIndex(i)];elementData[realIndex(i)] = null;}elementData = objects;}public int size(){return size;}public boolean isEmpty(){return size==0;}public boolean contins(Object o){return indexOf(o)!=-1;}//error 0->oprivate int indexOf(Object o) {for (int i=0;i<size;i++){if (Objects.equals(elementData[realIndex(i)],o)){return i;}}return -1;}private int lastIndexOf(Object o) {for (int i=size-1;i>=0;i--){if (Objects.equals(elementData[realIndex(i)],0)){return i;}}return -1;}public void clear(){for (int i=0;i<size;i++){elementData[realIndex(i)] = null;}saveCapacity(size);size = 0;}public Object[] toArray(){Object[] objects = new Object[size];for (int i=0;i<size;i++){objects[i] = elementData[realIndex(i)];}return objects;}public <T> T[] toArray(T[] a){if(a.length<size){a = (T[])Array.newInstance(a.getClass().getComponentType(),size);}Object[] o = a;for (int i=0;i<size;i++){o[i] = elementData[realIndex(i)];}if (a.length<size){a[size] = null;}return a;}//no Comparetorpublic void sort(Comparator<? super E> comparator){trimToSize();Arrays.sort((E[])elementData,0,size,comparator);}public void add(E e){ensureCapacityInternal(size+1);elementData[realIndex(size++)] = e;}private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculate(minCapacity));}private void ensureExplicitCapacity(int minCapacity) {if (minCapacity>elementData.length){grow(minCapacity);}}//no deal headprivate void grow(int minCapacity) {int oldCapacity = elementData.length;int newCapacity = oldCapacity + oldCapacity>>1;if (newCapacity<minCapacity){newCapacity = minCapacity;}if (newCapacity>MAX_ARRAY_SIZE){newCapacity = (minCapacity>MAX_ARRAY_SIZE)?Integer.MAX_VALUE:MAX_ARRAY_SIZE;}Object[] objects = new Object[newCapacity];for (int i=0;i<size;i++){objects[i] = elementData[realIndex(i)];}elementData = objects;head = 0;}private int calculate(int minCapacity) {if (elementData == EMPTY_ELEMENTDATA){minCapacity = Math.max(minCapacity,DEFAULT_CAPACITY);}return minCapacity;}//error no ensureCapacityInternal()//i>=index no deal indexpublic void add(int index,E e){rangeCheckForAdd(index);ensureCapacityInternal(size+1);if (index<(size>>1)){for (int i=0;i<index;i++){elementData[realIndex(i-1)] = elementData[realIndex(i)];}head = head-1;}else {for (int i=size-1;i>=index;i--){elementData[realIndex(i+1)] = elementData[realIndex(i)];}}elementData[realIndex(index)] = e;size++;}@Override public String toString() {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("CircleArrayList{size=").append(size).append(", head=").append(head).append(", elementData=[");for (int i=0;i<size;i++){if (i==0){stringBuilder.append(elementData(i));continue;}stringBuilder.append(", "+elementData(i));}stringBuilder.append("]}");return stringBuilder.toString();}public String toRealString() {return "NewRealArrayList{" +"size=" + size +", head=" + head +", elementData=" + Arrays.toString(elementData) +'}';}private void rangeCheckForAdd(int index) {if (index<0||index>size)throw new IndexOutOfBoundsException();}private void rangeCheck(int index) {if (index<0||index>=size)throw new IndexOutOfBoundsException();}public E remove(int index){rangeCheck(index);E e = elementData(index);if (index<(size>>1)){for (int i=index-1;i>=0;i--){elementData[realIndex(i+1)] = elementData[realIndex(i)];}elementData[head] = null;head = head+1;}else {for (int i=index+1;i<size;i++){elementData[realIndex(i-1)] = elementData[realIndex(i)];}elementData[realIndex(size-1)] = null;}size--;saveCapacity(size);return e;}//error no deal headprivate void saveCapacity(int size) {if (size<(elementData.length>>1)){Object[] objects = new Object[elementData.length>>1];for (int i=0;i<size;i++){objects[i] = elementData[realIndex(i)];elementData[realIndex(i)] = null;}elementData = objects;head=0;}}private E elementData(int index){return (E)elementData[realIndex(index)];}public E remove(E e){int i = indexOf(e);return remove(i);}public E set(int index,E e){E oe = elementData(index);elementData[realIndex(index)] = e;return oe;}public E get(int index){return elementData(index);}
}
测试类
package datastructure.linearlist;public class CircleArrayListTest {public static void main(String[] args) {HtqCircleArrayList circleArrayList = new HtqCircleArrayList(10);System.out.println("初始化10,添加8个元素:");circleArrayList.add(1);circleArrayList.add(2);circleArrayList.add(3);circleArrayList.add(4);circleArrayList.add(5);circleArrayList.add(6);circleArrayList.add(7);circleArrayList.add(8);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("删除第一个元素:");circleArrayList.remove(0);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("删除最后一个元素(此时元素有7个索引是6):");circleArrayList.remove(6);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("结尾添加一个元素:");circleArrayList.add(9);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("删除索引为1的元素(测试删除前半的元素):");circleArrayList.remove(1);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("删除索引为4的元素(测试删除前半的元素):");circleArrayList.remove(4);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("删除索引为2的元素(测试删除中间的元素):");circleArrayList.remove(2);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("在索引为1的位置添加元素(测试添加前半的元素):");circleArrayList.add(1,331);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("在索引为3的位置添加元素(测试添加后半的元素):");circleArrayList.add(3,551);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("结尾添加一个元素:");circleArrayList.add(10);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("在索引为3的位置添加元素(测试添加中间的元素):");circleArrayList.add(3,550);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("在索引为5的位置添加两个元素(测试绕环):");circleArrayList.add(5,553);circleArrayList.add(5,552);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("删除刚才添加的两个元素(测试删除对象):");circleArrayList.remove((Object)553);circleArrayList.remove((Object)552);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("在索引为2的位置添加两个元素(测试前绕环):");circleArrayList.add(2,333);circleArrayList.add(2,332);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());System.out.println("在索引为5的位置添加一个元素(测试扩容):");circleArrayList.add(5,441);System.out.println(circleArrayList);System.out.println(circleArrayList.toRealString());}
}
动态循环数组(ArrayList优化)相关推荐
- android动态扩容数组,ArrayList 扩容 Android Java 真的不一样
以前学java基础的时候 看过ArrayList的扩容机制 实现原理是下面这样 当时做的笔记 ArrayList扩容机制 在jdk1.7前是 *3/2+1 在jdk1.7开始就是 old+(old&g ...
- 动态数组ArrayList c# 1613536290
动态数组ArrayList c# 1613536290 导入命名空间 using System.Collections; 实例化对象 空对象 ArrayList 对象 = new ArrayList( ...
- java二维数组添加元素_Java二维数组与动态数组ArrayList类详解
java二维数组 java 语言中提供的数组是用来存储固定大小的同类型元素. 1.二维数组初始化和声明 数组变量的声明,和创建数组可以用一条语句完成,如下所示: int a[][] = new int ...
- 力扣【下一个更大元素】leetcode-503.下一个更大元素 Ⅱ:单调栈解法+循环数组解法
题目: 思路与解法: 1.如果是暴力法,只需要遍历就可以了,但是那样的话时间复杂度就是O(N^2); 2.可以把这几个数字,抽象成为高度不一样的柱子: 3.寻找的过程,就是从当前柱子去看,被后面的哪一 ...
- 约瑟夫问题的学习(基于循环链表)以及基于循环数组
这是17世纪法国数学家加斯帕在<数目中的游戏问题>讲的一个问题:15个教徒和15个非教徒在海上遇险,必须将一般的人投入海中,其他的人才能幸免于难.与实现各一个办法:30个人围成一个圈,从第 ...
- java 循环map 优雅写法_Java for循环Map集合优化实现解析
这篇文章主要介绍了java for循环map集合优化实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在<for循环实战性能优化> ...
- for循环之性能优化
前言 for循环是开发时常用的语法之一,比如对数组,集合的遍历等,但是如果使用不好也会出现很多新能损耗的问题,今天就来讲解一下for循环的常用性能优化问题. 嵌套循环 嵌套循环是有俩层或者俩层以上的循 ...
- 《恋上数据结构第1季》动态扩容数组原理及实现
动态扩容数组 什么是数据结构? 线性表 数组(Array) 动态数组(Dynamic Array) 动态数组接口设计 清除所有元素 - clear() 添加元素 - add(E element).ad ...
- C/C++动态开辟数组【C++:new/delete(推荐):int *arr = new int[m];】【C++:vector】【C:malloc() free()】
一.C++的new/delete(推荐) 1.动态开辟一维数组 #include<iostream> #include<stdio.h>using namespace std; ...
最新文章
- ScaleYViewPager
- BERT+CRF的损失函数的研究
- module 'torch.jit' has no attribute 'unused'
- MySQL 5.7 安装指南
- 硬刚一周,3W字总结,一年的经验告诉你如何准备校招,拿大厂offer
- 与 SENet 互补提升,华为提出自注意力新机制:Weight Excitation
- 小学计算机说课稿,小学信息技术说课稿《新建文件夹》
- html的带分页的表格写法,Html表格分页
- CUDA零拷贝内存(zerocopy memory)
- Timeline的Animation Track详解
- excel查找空值快捷键_『EXCEL定位条件快捷键』excel定位空值填充
- 郁金香商业辅助教程 2016 笔记 1~5
- VP9编码:迄今的尝试
- 关于app的几个核心功能的设计想法
- 美国3D理发师可剪出球星脸发型
- Excel按照固定行数拆分为多个文件
- Opencv__模板匹配(上)
- Palo, Palo
- centos挂载u盘只读_解决CentOS自动挂载U盘/SD Card被识别为只读文件系统
- Vulkan的基本概念:如何使用Vulkan绘制三角形?
热门文章
- 开车的人和不开车的人思维有什么区别?
- 按键精灵大漠插件使用基础练习入门代码
- ultraedit编译java_在UltraEdit中编译和运行Java程序
- 北京市中 高英语听说计算机考,北京市教育委员会关于听力及言语障碍考生参加2019年中考英语听说计算机考试有关事项的通知...
- vue 数字动画递增_数字滚动动画效果 vue组件化
- matlab获取图像某点RGB值、灰度值的方法
- Java简单项目 水果摊
- 如何更高好地管理待办事项?
- java,NIO,UDP协议网络通信DEMO
- Python 文件 tell() 方法