一、类与成员变量
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList继承自AbstractSequentialList抽象类,实现了List<E>、 Deque、Cloneable、Serializable接口。
其中:
Deque是Queue的子接口是双向队列,它支持从两个端点方向检索和插入元素。
实现Cloneable接口的类的对象允许被克隆。同时该类需要重写Object类的clone方法。
实现Serializable接口,即采用了Java默认的序列化机制。
private transient Entry<E> header = new Entry<E>(null, null, null); private transient int size = 0;
header是双向链表的头节点,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量: previous, next, element。其中,previous是该节点的上一个节点,next是该节点的下一个节点,element是该节点所包含的值。
size是双向链表中节点实例的个数。、
其中Entry类的源码
private static class Entry<E> { E element; Entry<E> next; Entry<E> previous; Entry(E element, Entry<E> next, Entry<E> previous) { this.element = element; this.next = next; this.previous = previous; } }
节点类很简单,element存放业务数据,previous与next分别存放前后节点的信息(在数据结构中我们通常称之为前后节点的指针)。
二、构造:
public LinkedList() { header.next = header.previous = header; } public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
三、操作LinkedList
添加
private Entry<E> entry(int index) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+size); Entry<E> e = header; if (index < (size >> 1)) { for (int i = 0; i <= index; i++) e = e.next; } else { for (int i = size; i > index; i--) e = e.previous; } return e; }
public boolean addAll(Collection<? extends E> c) { return addAll(size, c); } // index参数指定collection中插入的第一个元素的位置 public boolean addAll(int index, Collection<? extends E> c) { // 插入位置超过了链表的长度或小于0,报IndexOutOfBoundsException异常 if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+size); Object[] a = c.toArray(); int numNew = a.length; // 若需要插入的节点个数为0则返回false,表示没有插入元素 if (numNew==0) return false; modCount++;//否则,插入对象,链表修改次数加1 // 保存index处的节点。插入位置如果是size,则在头结点前面插入,否则在获取index处的节点插入 Entry<E> successor = (index==size ? header : entry(index)); // 获取前一个节点,插入时需要修改这个节点的next引用 Entry<E> predecessor = successor.previous; // 按顺序将a数组中的第一个元素插入到index处,将之后的元素插在这个元素后面 for (int i=0; i<numNew; i++) { // 结合Entry的构造方法,这条语句是插入操作,相当于C语言中链表中插入节点并修改指针 Entry<E> e = new Entry<E>((E)a[i], successor, predecessor); // 插入节点后将前一节点的next指向当前节点,相当于修改前一节点的next指针 predecessor.next = e; // 相当于C语言中成功插入元素后将指针向后移动一个位置以实现循环的功能 predecessor = e; } // 插入元素前index处的元素链接到插入的Collection的最后一个节点 successor.previous = predecessor; // 修改size size += numNew; return true; }
private Entry<E> addBefore(E e, Entry<E> entry) { Entry<E> newEntry = new Entry<E>(e, entry, entry.previous); newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; size++; modCount++; return newEntry; } public boolean add(E e) { addBefore(e, header); return true; } public void add(int index, E element) { addBefore(element, (index==size ? header : entry(index))); } public void addFirst(E e) { addBefore(e, header.next); } public void addLast(E e) { addBefore(e, header); }