ArrayList和LinkedList都实现了List接口。
ArrayList是基于索引的数据结构,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问, 但是要随机插入或删除数据却是开销很大的,因为这需要重排数组中的所有数据。在ArrayList的当前容量足够大时,向最后插入数据开销很小(时间复杂度O(1)),在ArrayList的当前容量不足时,需要进行扩容。
LinkedList基于双向链表,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引,只需要改变指针指向即可。LinkedList由于需要存储每个节点的prev和next,所以需要的内存更多。
ArrayList
get(index)读取下标,时间复杂度O(1)
transient Object[] elementData;
public E get(int index) {
Objects.checkIndex(index, size);
return elementData(index);
}
E elementData(int index) {
return (E)elementData[index];
}
add(E)向队尾插入数据
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
private void add(E e, Object[] elementData, int s) {
// 当容量不足时,进行扩容
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
private Object[] grow() {
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// newCapacity为计算出的新容量
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
add(index, E)向指定位置插入数据
调用System.arraycopy
public void add(int index, E element) {
rangeCheckForAdd(index);
modCount++;
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)
elementData = grow();
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = element;
size = s + 1;
}
remove:无论是remove(index)还是remove(E),调用的都是fastRemove(Object[] es, int i),remove(index)直接调用fastRemove(时间复杂度O(1)),而remove(E)需要先遍历数组得到E的index(时间复杂度O(n))
最终调用System.arraycopy
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
if ((newSize = size - 1) > i)
System.arraycopy(es, i + 1, es, i, newSize - i);
es[size = newSize] = null;
}
LinkedList
get(index)读取下标,时间复杂度O(n)
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int index) {
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
add(E)向后插入数据
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
// 新节点的上一个节点为之前的last节点
final Node<E> newNode = new Node<>(l, e, null);
// 当前的last节点为新节点
last = newNode;
// 在本次插入之前LinkedList是一个空list,那么first和last均为新节点,且这个节点的next和prev均为null
if (l == null)
first = newNode;
else
// 之前的last节点的下一个节点为新节点
l.next = newNode;
size++;
modCount++;
}
add(index, E)向指定位置插入数据
a <-> b <-> c
假设node(index)拿到的是b
那么new的prev为a,next为b
修改b的prev为new
修改a的next为new
a <-> new <->b <-> c
public void add(int index, E element) {
checkPositionIndex(index);
// 当index==size时,相当于向尾部增加数据
if (index == size)
linkLast(element);
else
// node(index)同样在get(index)时被调用,时间复杂度O(n)
linkBefore(element, node(index));
}
void linkBefore(E e, Node<E> succ) {
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
remove(index)
public E remove(int index) {
checkElementIndex(index);
// node(index)同样在get(index)时被调用,时间复杂度O(n)
return unlink(node(index));
}
remove(E)
遍历链表找到E,时间复杂度O(n)
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
unlink
a <-> b <-> c
假设需要删除的是b
修改a的next为c
修改c的prev为a
a <-> c
unlink(Node<E> x) {
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
网友评论