首先
定义ArrayList类,类中定义所需参数
/**
* 元素的数量
*/
private int size;
/**
* 所有的元素
*/
private E[] elements;
private static final int DEFAULT_CAPACITY = 10;
private static final int ELEMENT_NOT_FOUND = -1;
有参构造:数组默认大小为10,小于10则取默认
public ArrayList(int capaticy) {
capaticy = (capaticy < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capaticy;
elements = (E[]) new Object[capaticy];
}
无参构造:创建默认大小为10的数组
public ArrayList() {
this(DEFAULT_CAPACITY);
}
清除元素:数组中如果存入的是引用类型,那么数组节点存储的是该引用对象的内存地址,将所有节点的内存置空,就相当于清除所有节点
/**
* 清除所有元素
*/
public void clear() {
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
}
返回元素数量
/**
* 元素的数量
* @return
*/
public int size() {
return size;
}
判断元素是否空:
/**
* 是否为空
* @return
*/
public boolean isEmpty() {
return size == 0;
}
查看元素索引:若查看的这个元素为null(java是支持将对象数组存入空值的),所以首先判断该元素是否是空,若是,则返回该索引下标。若不为空,则开始非空比较,可以用到equal方法。
/**
* 查看元素的索引
* @param element
* @return
*/
public int indexOf(E element) {
if (element == null) { // 1
for (int i = 0; i < size; i++) {
if (elements[i] == null) return i;
}
} else {
for (int i = 0; i < size; i++) {
if (element.equals(elements[i])) return i; // n
}
}
return ELEMENT_NOT_FOUND;
}
是否包含某个元素
/**
* 是否包含某个元素
* @param element
* @return
*/
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
从某个位置插入一个元素:首先要考虑用户输入的这个位置是否已超过数组的界限
//越界校验
private void rangeCheckForAdd(int index) {
if (index < 0 || index > size) {
outOfBounds(index);
}
}
抛异常方法:
private void outOfBounds(int index) {
throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size);
}
因为是动态数组,插入后涉及到扩容问题,扩容采取了new出一个比之前数组更大的数组,承载之前数组中的数据,大小自取,这里是1.5倍。做法是利用到了位运算,这样比在原长度上直接*1.5倍效率高。
扩容方法的第一步,就是判断输入的容量数capacity是否比数组之前的oldCapacity小,若小,则直接返回(防止用户输错而报错,或者是胡乱输入),增加了程序的健壮性。这个点虽小,却值得学习。
最后将旧数据for循环转移至新数组,然后旧数组头部指向新数组的内存地址,完成。
/**
* 扩容方法
* 保证要有capacity的容量
* @param capacity
*/
private void ensureCapacity(int capacity) {
int oldCapacity = elements.length;
if (oldCapacity >= capacity) return;
// 新容量为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
E[] newElements = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
elements = newElements;
System.out.println(oldCapacity + "扩容为" + newCapacity);
}
在指定位置插入元素:越界检查–>扩容–>插入部位挨个后移–>size自增
/**
* 在index位置插入一个元素
* @param index
* @param element
*/
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacity(size + 1);
for (int i = size; i > index; i--) {
elements[i] = elements[i - 1];
}
elements[index] = element;
size++;
}
改变数组某一位置的值:首先也是越界检查,但是与添加方法不同,此时输入的index参数是不能等于数组长度的,必须严格小于,因此index等于size,也算越界。
private void rangeCheck(int index) {
if (index < 0 || index >= size) {
outOfBounds(index);
}
}
将旧值替换,然后返回
/**
* 设置index位置的元素
* @param index
* @param element
* @return 原来的元素ֵ
*/
public E set(int index, E element) {
rangeCheck(index);
E old = elements[index];
elements[index] = element;
return old;
}
将元素添加至数组尾部:直接调用之前的add方法,index参数写到数组末尾即可(即数组的长度)
/**
* 添加元素到尾部
* @param element
*/
public void add(E element) {
add(size, element);
}
输入索引值,取得索引对应的值:越界检验–>取值
/**
* 获取index位置的元素
* @param index
* @return
*/
public E get(int index) {
rangeCheck(index);
return elements[index];
}
移除某一位置的元素,且返回:越界检验–>新旧赋值–>元素前移–>删除元素内容置空,数组长度减一
/**
* 删除index位置的元素
* @param index
* @return
*/
public E remove(int index) {
rangeCheck(index);
E old = elements[index];
for (int i = index + 1; i < size; i++) {
elements[i - 1] = elements[i];
}
elements[--size] = null;
return old;
}
以上是我对于恋上数据结构视频中,动态数组部分的总结。