1. ArrayList子类
ArrayList是JavaCollection接口下List子接口的实现子类。它是一个长度可变的数组,底层是以数组为基础的顺序表实现的。所以说研究Java顺序表数据结构必须得了解一下ArrayList类。
// ArrayList定义
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
2. 顺序表
顺序表是数据结构表的表现形式之一,关于顺序表的概念这里就不加赘述了,可以参考下面的文章进行进一步的了解:
C语言顺序表及相关函数实现
接下来,我们实现一个以JDK提供的ArrayList类为蓝本的可以自动扩容的动态顺序表。
package myArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
// ArrayList 顺序表的实现
public class MyArrayList<T> implements Iterable<T> {
// 初始数组大小
private static final int DEFAULT_CAPACITY = 10;
// 当前数组大小
private int theSize;
// 存储数据的泛型数组
private T[] theItems;
// 无参构造,构造时初始化顺序表
public MyArrayList() {
doClear();
}
// 清空顺序表
public void doClear() {
clear();
}
// 将真正的clear()操作封装,提高程序的层次性
private void clear() {
this.theSize = 0;
// 设置数组大小为初默认值
ensureCapacity(DEFAULT_CAPACITY);
}
// 返回当前顺序表大小
public int size() {
return this.theSize;
}
// 当前顺序表是否为空
public boolean isEmpty() {
if(this.theSize == 0) {
return true;
}
return false;
}
// 自动调整当前数组大小,不浪费空间
public void trimToSize() {
// 将数组大小调整为当前数组大小
ensureCapacity(this.theSize);
}
// 将数组扩容到指定大小
@SuppressWarnings("unchecked")
public void ensureCapacity(int len) {
if(len < this.theSize) {
return;
}
// 保存旧的数组引用
T[] old = this.theItems;
// theItems指向新的数组对象
this.theItems = (T[])new Object[len];
// 值的拷贝
for(int i = 0; i < this.theSize; i++) {
this.theItems[i] = old[i];
}
}
// ArrayList的灵魂方法set/get
// set方法设置数组指定下标的值并返回修改之前的值
public T set(int index, T newValue) {
// 数组下标越界,抛出异常
if(index>=this.theSize || index<0) {
throw new ArrayIndexOutOfBoundsException();
}
T oldValue = this.theItems[index];
this.theItems[index] = newValue;
return oldValue;
}
public T get(int index) {
// 数组下标越界
if(index>=this.theSize || index<0) {
throw new ArrayIndexOutOfBoundsException();
}
return this.theItems[index];
}
// 插入元素,尾插. 顺序表插入删除要移动数组进行数据拷贝,时间复杂度为O(n),尾插是插入的一种特殊情况
public boolean add(T newValue) {
add(theSize, newValue);
// 尾插一定会成功
return true;
}
// 在指定下标处插入元素
public void add(int index, T newValue) {
// 数组已满,扩容
if(this.theItems.length == this.theSize) {
// 这里的扩容策略自定义,我设置为 当前数组大小*2+1
ensureCapacity((this.theSize)*2+1);
}
// 从后向前拷贝数据
for(int i = this.theSize; i-1>=index; i--) {
this.theItems[i] = this.theItems[i-1];
}
this.theItems[index] = newValue;
this.theSize++;
}
// 删除指定下标元素,返回删除的值
public T remove(int index) {
// 下标越界,抛出异常
if(index>=this.theSize || index<0) {
throw new IndexOutOfBoundsException();
}
// 保存删除的值
T removeValue = this.theItems[index];
// 从删除处向后移动数组
for(int i = index; i < this.theSize-1; i--) {
this.theItems[i] = this.theItems[i+1];
}
this.theSize--;
return removeValue;
}
// 因为java.util.ArrayList包中提供的ArrayList实现了Iterator接口,覆写了其中的iterator方法,但是这部分内容与顺序表无关,有兴趣可以看一下
@Override
public Iterator<T> iterator() {
// iterator方法返回一个一个Iterator的对象,这里直接返回下面内部类的对象
return new MyArrayListIterator();
}
// 内部类
private class MyArrayListIterator implements Iterator<T> {
private int count = 0;
@Override
public boolean hasNext() {
return theSize > count;
}
@Override
public T next() {
if(!hasNext()) {
throw new NoSuchElementException();
}
return theItems[count++];
}
@Override
public void remove() {
MyArrayList.this.remove(count--);
}
}
}