Java集合源码解读(3)-LinkedList的实现

LinkedList的实现其实是一个带哑头节点的双向循环链表。
1.LinkedList的字段
private transient Entry<E> header = new Entry<E>(null, null, null);
//Entry是一个LinkedList的内部类,其实就是链表上的节点,包含两个指针,一个指向
//前面节点,一个指向后面节点
   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中元素的数量
private transient int size = 0;

最后还有一个继承来的modCount字段。
2.构造方法
   /**
     * 默认设置哑头节点,其next和previous引用都指向它自己。形成了循环链表
     */
    public LinkedList() {
        header.next = header.previous = header;
    }
3.核心方法:
  (1) addBefore方法
//在指定节点前面增加一个节点
private Entry<E> addBefore(E e, Entry<E> entry) {
//首先构建一个新的Entry节点,其next引用指向指定的节点entry,其
           //previous引用指定节点原来的前面的节点
         Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
//调整newEntry的前面节点的next引用指向newEntry
         newEntry.previous.next = newEntry;
         //调整newEntry的后面节点的previous引用指向newEntry
newEntry.next.previous = newEntry;
size++;
modCount++;
return newEntry;
    }
(2)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)) { //size>>1等效于size/2,但是移位运算
              //效率更高
            for (int i = 0; i <= index; i++)
                e = e.next;
        } else {
            for (int i = size; i > index; i--)
                e = e.previous;
        }
        return e;
    }
4.有了上面的两个核心方法,增加和删除的方法主要以这两个方法为基础的。
例如,
(1)
public void add(int index, E element) {
        //如果在最后增加一个元素,就指定的节点就是哑头节点,由于是循环链表,
         //在最后增加一个元素,它的后面的元素当然是头节点了。如果索引位置不是
         //在最后,则先用entry方法得到指定索引位置的元素。之后再调用addBefore
        //方法。
        addBefore(element, (index==size ? header : entry(index)));
}
(2)
  //删除指定索引位置的元素,也是先调用entry方法得到相应的元素,再进行删除操作。
  public E remove(int index) {
        return remove(entry(index));
    }

    private E remove(Entry<E> e) {
if (e == header)
    throw new NoSuchElementException();

        E result = e.element;
e.previous.next = e.next;
e.next.previous = e.previous;
        e.next = e.previous = null;
        e.element = null;
size--;
modCount++;
        return result;
    }
5.其他方法
(1)
//删除一个对象,分对应的引用o是null还是非null两种情况。
public boolean remove(Object o) {
        if (o==null) {
            for (Entry<E> e = header.next; e != header; e = e.next) {
                if (e.element==null) {
                    remove(e);
                    return true;
                }
            }
        } else {
            for (Entry<E> e = header.next; e != header; e = e.next) {
                if (o.equals(e.element)) {
                    remove(e);
                    return true;
                }
            }
        }
        return false;
    }
(2)
//查找元素o,也是分o为null和非null两种情况,但是不管是哪一种情况,都是顺序查找

public int indexOf(Object o) {
        int index = 0;
        if (o==null) {
            for (Entry e = header.next; e != header; e = e.next) {
                if (e.element==null)
                    return index;
                index++;
            }
        } else {
            for (Entry e = header.next; e != header; e = e.next) {
                if (o.equals(e.element))
                    return index;
                index++;
            }
        }
        return -1;
    }
6. 由于LinkedList实现了双端队列Deque这个接口,因此,也具有双端队列操作的相关方法。因此,LinkedList可以当作先进先出的队列使用,也可以当作先进后出的堆栈使用。
7. LinkedList实现了迭代器
但是,这个迭代器的是实现ListIterator接口的,也就是说,可以向前或者向后进行迭代。

你可能感兴趣的:(java)