纯手撕动态数组(ArrayList)

2 阅读2分钟

package test; /*

  • 总结:这个没啥特别难的跟坑点,我当时刚学也没花啥时间就写完了。

  • 主要就只有一个扩容问题,难点应该就是用的System.arrayCopy的4个参数的理解。

  • 我当时基本就纯靠猜的参数,然后画图就搞定扩容的问题了。

  • 心得就是学会画图去具象化问题。 */ public class MyArrayTest {

    public static void main(String[] args) { MyArrayList mal = new MyArrayList(); mal.add(1); mal.add(2); mal.insert(0, 11); mal.insert(0, 12); mal.insert(0, 13); mal.insert(0, 14); mal.insert(0, 15); mal.insert(0, 16); mal.insert(0, 17); mal.insert(0, 18); mal.insert(0, 4); mal.insert(0, 5); mal.insert(0, 0); mal.insert(0, 7); mal.insert(0, 0); mal.insert(0, 5); mal.insert(0, 6); mal.insert(0, 2); mal.insert(0, 0); mal.remove(0); for(int i=0; i<mal.objs.length;i++) { System.out.println(mal.objs[i]); }

     System.out.println(mal.index);
     System.out.println(mal.objs.length);
     
    

    } }

class MyArrayList{ //底层是数组。所以有序可以重复。 Object[] objs; //用来定位目标元素以及判断数组列表是否为空的。 int index = -1; public MyArrayList() { //初始化容量为16 this(new Object[16]); }

public MyArrayList(Object[] objs) {
	//有参构造强制数组长度为2的幂。并重新封装防止外部直接修改。外部数组元素内部有null会有bug懒得改了。
	if(objs == null) {
		this.objs = new Object[16];
		return;
	}
	int capacity = Math.max(16, objs.length);
	this.objs = new Object[capacity];
	System.arraycopy(objs, 0, this.objs, 0, objs.length);
	this.index = objs.length - 1;
}

public void display() {
	if(this.index == -1) return;
	for(int i=0;i<objs.length;i++) {
		System.out.println(objs[i]);
	}
}

public boolean contains(Object obj) {
	return (this.get(obj) >= 0) ? true : false;
}

private void capacity() {
	//数组扩容为原数组长度的2倍
	Object[] newArrayList = new Object[objs.length*2];
	System.arraycopy(objs, 0, newArrayList, 0, objs.length);
	this.objs = newArrayList;
}

public boolean add(Object obj) {
	if(obj == null) return false;
	//超出数组长度时触发扩容
	if(index == objs.length) {
		this.capacity();
	}
	//只对空元素进行赋值。刚开始学写考虑不周到。懒得改了。
	for(int i=0;i<objs.length;i++) {
		if(objs[i] == null) {
			objs[i] = obj;
			break;
		}
	}
	index++;
	return true;
}

public boolean insert(int index,Object obj) {
	if(obj == null) return false;
	//限制插入必须是在数组下标范围内包含尾部插入。
	if(index > this.index+1 || index < 0) return false;
	//插入时原数组容量满了,触发扩容。
	if(this.index+1 == objs.length) {
		this.capacity();
	}
	//尾插
	if(this.index+1 == index) {
		objs[index] = obj;
		this.index++;
		return true;
	}
	//复制原数组到新数组然后对预留的插入位置插入。
	Object[] newObjs = new Object[objs.length];
	System.arraycopy(objs, 0, newObjs, 0, index);
	System.arraycopy(objs, index, newObjs, index+1, objs.length-(index+1));
	this.objs = newObjs;
	objs[index] = obj;
	this.index++;
	return true;
}

public int get(Object obj) {
	//遍历获取
	if(obj == null || this.index == -1) return -1;
	for(int i=0;i<=index;i++) {
		if(obj.equals(objs[i])) {
			return i;
		}
	}
	return -1;
}

public boolean remove(Object obj) {
	if(obj == null || this.index == -1) return false;
	for(int i=0;i<=index;i++) {
		if(obj.equals(objs[i])) {
			//这里刚刚学集合没有考虑到先找到目标出循环再处理。不应该在循环内部直接操作。
			//创建新数组
			Object[] newObjs = new Object[objs.length];
			//处理这里自己画图操作容易看清楚是删除哪个下标。不然容易删错。
			System.arraycopy(objs, 0, newObjs, 0, i);
			System.arraycopy(objs, i+1, newObjs, i, objs.length-i-1);
			objs[index] = null;
			this.objs = newObjs;
			index--;
			return true;
		}
	}
	return false;
}

}