测试结果分析
动态数组有一个最大的弊端就是浪费内存空间,这个无法避免。
还有一个弊端就是添加删除都需要移动数组元素,最坏情况下要从头移动到尾,也就是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 check
public 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->o
private 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 Comparetor
public 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 head
private 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 index
public 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 head
private 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());
}
}