1、LinkedList基本原理
LinkedList是一个双向链表,底层基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储上一个元素节点、下一个元素节点信息等。其源码结构如下:
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
*上一个节点信息
* (last.next == null && last.item != null)
*/
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/下一个节点信息
transient Node<E> last;
/**
* Constructs an empty list.
*/
public LinkedList() {
}
//LinkedList类中的内部类
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;
}
}
从中可知:该链表结构由一个个Node<E>对象连接而成,每一个元素存储本身内存地址的同时还存储上一个元素节点、下一个元素节点信息等
(1)添加元素,源码如下:
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #addLast}.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
linkLast(e);
return true;
}
/**
* 作为最后一个元素链接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 //不是首节点,则将当前元素节点信息给前一个元素节点的next值,这样实现了双向链表结构
l.next = newNode;
size++;
modCount++;
}
(2)根据index索引删除指定位置的元素信息
/**
* Removes the element at the specified position in this list. Shifts any
* subsequent elements to the left (subtracts one from their indices).
* Returns the element that was removed from the list.
*
* @param index the index of the element to be removed
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
/**
* Unlinks non-null node x.
*/
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;
}
从代码可知,根据索引删除步骤如下:
a.根据索引index查询出具体的Node<E>对象
b.引出当前节点对象的上一个节点、下一个节点
c.将前一个节点的next值变为当前节点的下一个节点(prev.next = next)
d.当前节点的下一个节点d的prev值变为当前节点的前一个节点(next.prev = prev)
e.当前节点从链表中脱离出来,内容item设置为null
2、LinkedList与ArrayList的区别
(1)数据结构不同
LinkedList为双向链表结构,链表内存是散乱的;ArrayList底层为数组方式存储的线性结构,存储结构是有序的
(2)性能方面不同
a、LinkeList由于使用了链表的结构,因此不需要维护容量的大小。从这点上说,它比ArrayList有一定的性能优势
b、列表任意位置中增加(删除)元素时,LinkeList只要将指定位置插入(脱离),保存前后元素节点信息,即可实现增加(删除)操作,其效率相对会快;ArrayList是基于数组实现的,而数组是一块连续的内存空间,如果在数组的任意位置插入元素,必然导致在该位置后的所有元素需要重新排列(即重新创建新的数组,重新分配元素位置),因此,其效率相对会比较低。
c、查询列表集合信息时性能差异:LinkeList(链表内存是散乱的)按序号索引数据需要进行前向或后向遍历查询,效率较低;ArrayList数据结构具有一定的排列顺序(根据索引能直接获取结果arr[i],因为底层为数组,不需要遍历),查询较高