LinkedList源码阅读

Collection类结构

Collection接口下有三个子接口类型:ListSetQueue

java collection

LinkedList接口

LinkedList实现了ListDeque两种类型的接口,List接口就是顺序表,在上一节ArrayList中有介绍。

Deque是"double ended queue"缩写,代表一个线性的集合支持在两端插入和删除元素操作。Deque接口定义了通过两端头和尾访问元素的方法,包括插入、删除、检查等。每个方法存在两种形式:抛出异常如果失败、返回一个特定值(null或false等)。方法具体描述如下:

  First Element (Head) Last Element (Tail)
Type Throws exception Special value Throws exception Special value
Insert addFirst(e) offerFirst(e) addLast(e) offerLast(e)
Remove removeFirst() pollFirst() removeLast() pollLast()
Examine getFirst() peekFirst() getLast() peekLast()

Deque扩展了Queue接口,因此看以看做是个FIFO先进先出队列,元素是在队列尾部添加,头部删除。QueueDeque中方法对应关系如下:

Queue Method Equivalent Deque Method
add(e) addLast(e)
offer(e) offerLast(e)
remove() removeFirst()
poll() pollFirst()
element() getFirst()
peek() peekFirst()

Deque也可以当做LlIFO后进先出的栈,类似于集合类中的Stack。当用于栈时,元素从头部添加和删除,对应方法如下:

Stack Method Equivalent Deque Method
push(e) addFirst(e)
pop() removeFirst()
peek() peekFirst()

LinkedList实现

类的定义

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

成员

 private transient Entry<E> header = new Entry<E>(null, null, null);
 private transient int size = 0;

LinkedList采用双向链表,定义了一个头结点,Entry代表链表一个节点,header不包含有意义值,即使链表为空也有一个头结点,实际是一个带头节点的双向链表。

 private static class Entry<E> {
    E element;
    Entry<E> next;
    Entry<E> previous;
}

方法

构造方法负责初始化头节点的next和previouse引用,都指向自己本身。

public LinkedList() {
    header.next = header.previous = header;
}

add方法,addBefore(e,entry)实现在entry前面插入元素

public boolean add(E e) {
    addBefore(e, header);  //尾部添加
    return true;
}
private Entry<E> addBefore(E e, Entry<E> entry) {
    Entry<E> newEntry = new Entry<E>(e, entry, entry.previous); 
    //newEntry->next=entry,newEntry->previous=entry->previous
    newEntry.previous.next = newEntry; //entry->previous->next = newEntry
    newEntry.next.previous = newEntry; //entry->previous = newEntry
    size++;
    modCount++;
    return newEntry;
}
public void add(int index, E element) {
    addBefore(element, (index==size ? header : entry(index)));
}
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;
}

get方法

public E get(int index) {
    return entry(index).element;
}
public E getFirst() {
    if (size==0)
        throw new NoSuchElementException();
    return header.next.element;
}

其他操作如remove等,不一一介绍,主要是涉及链表操作,注意该链表是带一个头结点。

迭代器的实现

支持单向和双向迭代器,默认都是调用内部类LinkedList$ListItr类实现

类定义

private class ListItr implements ListIterator<E> {
    private Entry<E> lastReturned = header; 
    private Entry<E> next; //当前遍历位置
    private int nextIndex; //当前index
    private int expectedModCount = modCount;
}

方法

ListItr(int index) {
    if (index < 0 || index > size)
    throw new IndexOutOfBoundsException("Index: "+index+
                        ", Size: "+size);
    if (index < (size >> 1)) { //前半部分查找
        next = header.next;
    	for (nextIndex=0; nextIndex<index; nextIndex++)
        	next = next.next;
    } else {
        next = header;
   	for (nextIndex=size; nextIndex>index; nextIndex--)
        	next = next.previous;
    }
}

public boolean hasNext() {
    return nextIndex != size;
}

public E next() {
    checkForComodification();
    if (nextIndex == size)
        throw new NoSuchElementException();
    lastReturned = next;
    next = next.next;
    nextIndex++;
    return lastReturned.element;
}

public boolean hasPrevious() {
    return nextIndex != 0;
}

public E previous() {
    if (nextIndex == 0)
        throw new NoSuchElementException();
    lastReturned = next = next.previous;
    nextIndex--;
    checkForComodification();
    return lastReturned.element;
}

ArrayList中的迭代器实现类似,通过内部类直接访问外部类的成员和方法实现遍历操作,不过由于采用链表方式,多了一个next指向链表遍历位置的引用元素。

总结

  1. LinkedList实现了ListDeque接口,其中Deque是一个双端队列,可以在头部和尾部两端添加和删除元素,因此LinkedList既可以当作先进先出的队列,也可以当作后进先出的栈。
  2. LinkedList采用双向链表方式实现,因此插入、删除元素效率比较高,但不支持随机访问。
  3. 多线程环境下LinkedList不能保证线程安全,因此对其结构修改的操作应当程序员来保证线程安全,其迭代器支持fail-fast,迭代过程中试图检测修改,若修改了容器则抛出ConcurrentModificationException
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值