鏈表是很常見(jiàn)的一種數(shù)據(jù)結(jié)構(gòu)。通常有兩種實(shí)現(xiàn)方式:一種是使用數(shù)組,一種使用指針。數(shù)組涉及數(shù)據(jù)移動(dòng)和擴(kuò)容問(wèn)題,但隨機(jī)查找方便;指針插入刪除方便,但隨機(jī)查找不方便
下面學(xué)習(xí)java的ArrayList,鏈表的數(shù)組實(shí)現(xiàn),仿照精簡(jiǎn)版
常見(jiàn)方法:add、get、remove、size、isEmpty等,簡(jiǎn)單起見(jiàn)就不抽取父類(lèi)了
ArrayList每次擴(kuò)容50% (newCapacity + (newCapacity >> 1)),右移1位相當(dāng)于除2
public class MyArrayList<T> implements Iterable<T> {
/** 默認(rèn)容量 */
private static final int DEFAULT_CAPACITY = 20;
/** size */
private int size;
/** data */
private transient Object[] data;
/** empty array */
private static final Object[] EMPTY_ELEMENTDATA = {};
public MyArrayList() {
data = new Object[DEFAULT_CAPACITY];
}
public MyArrayList(int capacity) {
if (capacity >= 0) {
data = new Object[capacity];
} else {
data = new Object[DEFAULT_CAPACITY];
}
}
public void add(T element) {
// 確認(rèn)容量是否足夠,不夠則擴(kuò)容
ensureCapacity(size + 1);
data[size++] = element;
}
public void add(int index, T element) {
// 檢查范圍
checkRange(index);
// 確認(rèn)容量是否足夠,不夠則擴(kuò)容
ensureCapacity(size + 1);
System.arraycopy(data, index, data, index + 1, size - index);
data[index] = element;
size++;
}
public T get(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException();
}
return elementData(index);
}
public T remove(int index) {
// 檢查范圍
checkRange(index);
// 獲取元素
T t = elementData(index);
// 移動(dòng)元素
int numMoved = size - index - 1;
if (numMoved > 0) {
System.arraycopy(data, index + 1, data, index, numMoved);
}
// 清空元素內(nèi)容
data[--size] = null;
return t;
}
void checkRange(int index) {
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException();
}
}
public int size() {
return this.size;
}
public boolean isEmpty() {
return size() == 0;
}
@SuppressWarnings("unchecked")
T elementData(int index) {
return (T) data[index];
}
private void ensureCapacity(int newCapacity) {
if (newCapacity < size) {
return;
}
// 擴(kuò)容,每次擴(kuò)容50%
int newSize = newCapacity + (newCapacity >> 1);
data = Arrays.copyOf(data, newSize);
}
/**
* 釋放多余的空間,剛發(fā)現(xiàn)有這么個(gè)功能....
*/
public void trimToSize() {
if (size >= data.length) {
return;
}
data = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(data, size);
}
@Override
public Iterator<T> iterator() {
return new ArrayListIterator();
}
/**
* 實(shí)現(xiàn)迭代接口,可以使用迭代器遍歷List
*/
private class ArrayListIterator implements Iterator<T> {
private int currentIndex;
@Override
public boolean hasNext() {
return currentIndex < size();
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return elementData(currentIndex++);
}
// // 暫不實(shí)現(xiàn)遍歷時(shí)刪除的操作
// @Override
// public void remove() {
// MyArrayList.this.remove(--currentIndex);
// }
}
}
ArrayList里有兩個(gè)好用的方法:
-
System.arraycopy(data, index + 1, data, index, size - index - 1);
數(shù)組中元素的移動(dòng)或者兩個(gè)數(shù)組之間元素的復(fù)制 -
Arrays.copyOf(data, newSize); // 這個(gè)方法也是剛發(fā)現(xiàn)的。
可以用來(lái)復(fù)制一個(gè)數(shù)組,從第一個(gè)元素開(kāi)始,如果newSize>data的長(zhǎng)度,則使用data的長(zhǎng)度