链表的概念在学c++的时候就接触了,就是一个个节点,每个节点里存在对下一个节点的引用。大概结构如下:
class Node{
//节点的其他属性
...
//引用下一个节点
Node next;
}
这样一个个节点上一个连下一个就形成了链表,概念很简单。如果知道第一个节点的内存地址,那么可以顺藤摸瓜找到其他节点。这种存储方式的好处是插入和删除时不需要做移动操作,只要改一下next的指向即可。缺陷也很明显,查找Node得从第一个节点依次遍历。
这里有几个概念:单链表,双端双向链表,循环链表等可以查一下。跟队列有点像,但是队列我们之前见过的那种是用数组存储的,实际上也可以用这种链表来存储。
java中链表比较典型的实现是LinkedList。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
//AbstractSequentialList
public abstract class AbstractSequentialList<E> extends AbstractList<E>
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>
从这里可以看出AbstractSequentialList包含了collection和list的实现.
我们上一节了解了collection中包含了各种操作以及迭代器。而list中其实也是collection
public interface List<E> extends Collection<E>
注意这里还有Deque,前面聊过这个是双端队列,所以这个LinkedList实际上是一个双端链表。通过first和last维护首尾节点
transient Node<E> first;
transient Node<E> last;
从addAll方法可以看到这个链表的构建过程。核心代码如下:
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
//通过for循环将所有node通过next连接起来
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
说白了就是开头我画的那点东西。