您的位置:首页 > 编程语言 > Java开发

Java记录 -49- LinkedList源码剖析

2015-10-29 00:41 441 查看
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable
List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现
List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。
此类实现 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。
所有操作都是按照双重链接列表的需要执行的。在列表中编索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。
LinkedList就是一个链表,其底层使用了双向链表来实现。
LinkedList的两个构造函数实现:
Entry作为节点,构造函数创建了一个空的双向链表。而带参数的构造函数则先调用了不带参数的构造函数,然后将传过来的集合里的元素都添加到链表里。

private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;
/**
* Constructs an empty list.
*/
public LinkedList() {
header.next = header.previous = header;
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param  c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
Entry作为链表节点,其实现如下:
Entry作为LinkedList的一个内部类实现。Entry实现了Node功能,element存放数据信息,next指向下一个节点,previous指向前一个节点。其构造函数中实现了数据赋值,和节点指向。

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;
}
}
LinkedList的add方法:
LinkedList的add方法调用了addBefore方法,并将header传入。在addBefore中先创建了一个Entry节点,然后修改指针指向。完全都是双向链表的操作。而在指定位置添加也是调用addBefore方法,只是没有直接传递header节点,而是传递了要添加位置的节点。

/**
* 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 <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
addBefore(e, header);
return true;
}
/**
* Inserts the specified element at the specified position in this list.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
addBefore(element, (index==size ? header : entry(index)));
}
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;
}
获取数据元素:
LinkedList适合挨个遍历元素,即使指定了位置查询,也需要挨个遍历,因为它只知道链表的头header位置,要通过header去寻找其他节点,比如下面的getFirst和getLast方法是最简单的,直接使用header就可以找到。但指定位置的get方法则需要调用entry定位节点的方法来实现,上面添加元素到指定位置时也需要调用entry方法来找到指定位置的节点。entry方法也是通过header来挨个遍历寻找节点。

public E get(int index) {
return entry(index).element;
}
public E getLast()  {
if (size==0)
throw new NoSuchElementException();
return header.previous.element;
}
public E getFirst() {
if (size==0)
throw new NoSuchElementException();
return header.next.element;
}
/**
* Returns the indexed entry.
*/
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: