1.1 LinkedList的数据结构
LinkedList与ArrayList类都实了List接口,但LinkedList与ArrayList不同的是,它是基于双向链表实现数据的存储,链表是由若干个Node对象组成。添加或删除元素时不需要移动其他元素。
1.2 扩容方式
由于它采用的使链表结构,所以它并不存在所谓的扩容方式,每次添加元素都会创建新的Node节点并分配空间,在内存中分配的空间并不连续。
2. 常用方法
2.1 添加元素
2.1.1 boolean add(E e):默认将元素添加到链表尾部,若添加成功返回true。
public boolean add(E e) {
linkLast(e);
return true;
}
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++;
modCount++;
}
添加元素底层源码(linkLast方法):将链表尾结点指向结点l,同时创建新结点并将新添加元素放入新结点。再将新结点指向尾结点。接下来判断结点l是否为空,若是,则新结点既是头结点也是尾结点;否则将新结点指向l结点的下一个结点。最后链表长度加一。
2.1.2 void addFirst(E e):将元素添加到集合头部。
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
2.1.3 void addLast(E e):将元素添加到集合头部。
public void addLast(E e) {
linkLast(e);
}
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++;
modCount++;
}
2.2 获取元素
2.2.1 E get(int index):get方法是通过遍历链表,查找指定下标出的元素,并且返回该元素。
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
2.2.2 E getFirst():获取链表中头元素。
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
2.2.3 E getLast():获取链表中尾元素。
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
2.3 查找元素
2.3.1 int indexOf(Object o):indexOf方法查找指定元素的下标位置,若存在返回下标值,否则返回-1。
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
indexOf方法底层源码实现:先定义一个计数器index,接着判断传入元素是否为空,若是,则遍历链表并判断元素是否为空,若是空就返回index(下标);若传入元素不为空,则判断链表元素是否等于传入元素,若等于则返回index(下标)。若没有则返回-1。
2.3删除元素
2.3.1 E remove():删除链表头元素,返回删除元素。
boolean remove(Object o):删除链表中指定元素。若删除成功,返回true;否则返回false。
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;
}
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;
}
底层源码:删除元素x,next为x下一个节点,prev为x的前一个节点,若prev为空,说明x为头结点,删除后next为头结点;next指向prev的下一个结点且x的前一个节点置空。next结点同理;最后链表长度减一。
2.3.2 E remove (int index):删除指定下标元素,返回删除元素。
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
2.3.3 E removeFirst():删除链表头元素,返回删除元素。
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
2.3.4 E removeLast(): 删除链表尾元素,返回删除元素。
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
2.4 将链表转为数组
2.4.1 T[ ] toArray(T[ ] a):将链表转为数组,返回数组
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}
底层源码:创建一个数组result,遍历链表并将每个元素存入数组,最后返回数组。