系统环境 JDK1.7
LinkedList的基本结构 :在JDK1.6中LinkedList是双向引用的环形结构,JDK1.6中是双向引用的线性结构
提醒:看链表代码时最好用笔画下链表结构 有助于理解代码
成员变量
//存放当前链表有多少个节点 transient int size = 0; //为指向链表的第一个节点的引用 transient Node<E> first; //为指向链表的最后一个节点的引用 transient Node<E> last;
构造方法
1.不带参数的构造方法 public LinkedList() { } 2.带参数Collection的构造方法 public LinkedList(Collection<? extends E> c) { this(); addAll(c); } //具体实现是通过 addAll(size, c)方法 public boolean addAll(Collection<? extends E> c) { return addAll(size, c); }
addAll(size, c)方法
public boolean addAll(int index, Collection<? extends E> c) { // 检查传入的索引值是否在合理范围内 checkPositionIndex(index); // 将给定的Collection对象转为Object数组 Object[] a = c.toArray(); int numNew = a.length; // 数组为空的话,直接返回false if (numNew == 0) return false; // 数组不为空 Node<E> pred, succ; if (index == size) { // 构造方法调用的时候,index = size = 0,进入这个条件。 succ = null; pred = last; } else { // 链表非空时调用,node方法返回给定索引位置的节点对象 succ = node(index); pred = succ.prev; } // 遍历数组,将数组的对象插入到节点中 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; // 将当前链表最后一个节点赋值给last } else { // 链表非空时,将断开的部分连接上 pred.next = succ; succ.prev = pred; } // 记录当前节点个数 size += numNew; modCount++; return true; } 注:这段代码分为了2种情况,一个是原来的链表是空的(index == size),一个是原来的链表有值 //内部类Node 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; } }
总结:对于两种构造方法可以概括为:无参构造为空实现。有参构造传入Collection对象,将对象转为数组,并按遍历顺序将数组首尾相连,全局变量first和last分别指向这个链表的第一个和最后一个。
addFirst/addLast分析
public void addFirst(E e) { linkFirst(e); } private void linkFirst(E e) { final Node<E> f = first; // f 指向原链表首节点 final Node<E> newNode = new Node<>(null, e, f); // 创建新的节点,新节点的后继指向原来的头节点 first = newNode; // first 指向新创建的节点 if (f == null) last = newNode; else f.prev = newNode; // 原链表首节点的prev指向创建的新节点 size++; modCount++; } //同addFirst()类似 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++; }
get方法
public E get(int index) { // 校验给定的索引值是否在合理范围内 checkElementIndex(index); return node(index).item; } Node<E> node(int index) { //判断给定的索引值 //若索引值大于整个链表长度的一半,则从后往前找 //若索引值小于整个链表的长度的一般,则从前往后找 //整数右移一位 相当除2 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; } }
整理自《http://blog.csdn.net/zw0283/article/details/51132161》