LinkedList解析,与ArrayList优劣对比
2016-07-29 本文已影响272人
风风风筝
基于JDK1.8
只列出关键方法,关注初始化、add、get、remove
public LinkedList() { //默认没做任何操作
}
public boolean add(E e) {
linkLast(e);
return true;
}
transient Node<E> first;
transient Node<E> last;
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++; //size()方法返回值
modCount++;
}
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
能看出来是这样的结构:
first {pre=null; next = e1; item="a"}
e1 {pre=first; next=e2; item="b"}
e2 {pre=e1; next=e3; item="c"}
...
last {pre=en; next=null; item="x"}
看看get()实现
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;
}
}
如果index<size/2,则从头部往后查找,反之则从尾部往前查找。
再看remove()实现
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
E unlink(Node<E> x) {
// assert x != null;
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;
}
先找到index的Node,找到后做的事情也比较简单,比如原本是
first {pre=null; next = e1; item="a"}
e1 {pre=first; next=e2; item="b"}
e2 {pre=e1; next=e3; item="c"}
...
last {pre=en; next=null; item="x"}
remove(1)后
first {pre=null; next = e2; item="a"}
e2 {pre=first; next=e3; item="c"}
...
last {pre=en; next=null; item="x"}
与ArrayList对比
对于get()和set(),ArrayList优于LinkedList,因为LinkedList要遍历查找(最坏情况遍历次数=size/2),而数组可以直接定位。
对于add(index,element),ArrayList需要操作index后面的所有节点往后挪一个位,LinkedList只需修改前后2个node的指向,如果index不是最后一位,那么LinkedList效率更高,如果index是最后一位,实测还是ArrayList效率更高。
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
list.add(i);
} //耗时105ms
LinkedList<Integer> list = new LinkedList<>();
for (int i = 0; i < 1000000; i++) {
list.add(i);
} //耗时220ms
对于remove(index),ArrayList需要把index后面的值都往前挪一个位,LinkedList则需要遍历查找到该index所在的node。
for (int i = 0; i < 10000; i++) {
list.remove(i);
}
从第一位开始remove,ArrayList耗时4680ms,LinkedList耗时513ms
从末尾开始remove,ArrayList耗时4722ms,LinkedList耗时305ms
总结
get(index)、set(index, element) ArrayList绝对优势
add(element) ArrayList略胜一筹
add(index, element) index越小,ArrayList效率越低,平均来算LinkedList优势
remove() LinkedList绝对优势