LinkedList 双向循环链表和双向链表的区别
从JDK1.7开始,LinkedList 由双向循环链表改为双向链表
首先,简单介绍一下LinkedList:
LinkedList是List接口的双向链表实现。由于是链表结构,所以长度没有限制;而且添加/删除元素的时候,只需要改变指针的指向(把链表断开,插入/删除元素,再把链表连起来)即可,非常方便,而ArrayList却需要重整数组 (add/remove中间元素)。所以LinkedList适合用于添加/删除操作频繁的情况。
在JDK 1.7之前(此处使用JDK1.6来举例),LinkedList是通过headerEntry实现的一个循环链表的。先初始化一个空的Entry,用来做header,然后首尾相连,形成一个循环链表:
在LinkedList中提供了两个基本属性size、header。
private transient Entry<E> header = new Entry<E>(null, null, null); private transient int size = 0;
其中size表示的LinkedList的大小,header表示链表的表头,Entry为节点对象。
1 private static class Entry<E> { 2 E element; //元素节点 3 Entry<E> next; //下一个元素 4 Entry<E> previous; //上一个元素 5 6 Entry(E element, Entry<E> next, Entry<E> previous) { 7 this.element = element; 8 this.next = next; 9 this.previous = previous; 10 } 11 }
每次添加/删除元素都是默认在链尾操作。对应此处,就是在header前面操作,因为遍历是next方向的,所以在header前面操作,就相当于在链表尾操作。
如下面的插入操作addBefore以及图示,如果插入obj_3,只需要修改header.previous和obj_2.next指向obj_3即可。
1 private Entry<E> addBefore(E e, Entry<E> entry) { 2 //利用Entry构造函数构建一个新节点 newEntry, 3 Entry<E> newEntry = new Entry<E>(e, entry, entry.previous); 4 //修改newEntry的前后节点的引用,确保其链表的引用关系是正确的 5 newEntry.previous.next = newEntry; 6 newEntry.next.previous = newEntry; 7 //容量+1 8 size++; 9 //修改次数+1 10 modCount++; 11 return newEntry; 12 }
在addBefore方法中无非就是做了这件事:构建一个新节点newEntry,然后修改其前后的引用。
##########################################################################################################################################
在JDK 1.7,1.6的headerEntry循环链表被替换成了first和last组成的非循环链表。
transient int size = 0; /** * Pointer to first node. * Invariant: (first == null && last == null) || * (first.prev == null && first.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;
在初始化的时候,不用去new一个Entry。
/** * Constructs an empty list. */ public LinkedList() { }
在插入/删除的时候,也是默认在链尾操作。把插入的obj当成newLast,挂在oldLast的后面。另外还要先判断first是否为空,如果为空则first = obj。
如下面的插入方法linkLast,在尾部操作,只需要把obj_3.next指向obj_4即可。
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++; }
其中:
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; } }