jdk1.6 1.7 1.8 LinkedList源码实现原理及区别

LinkedList(jdk1.6)

private transient Entry header = new Entry(null, null, null);

定义一个空的Entry对象作为头结点,Entry是其内部定义的一个内部静态类,结构如下:

private static class Entry {
    E element;
    Entry next;
    Entry previous;

    Entry(E element, Entry next, Entry previous) {
        this.element = element;
        this.next = next;
        this.previous = previous;
    }
}

构造函数

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

即把首结点尾结点都指向头结点

 public E getFirst() {
    if (size==0)
        throw new NoSuchElementException();

    return header.next.element;
    }

获取元素首节点,如果链表中没有元素,会报NoSuchElementException错误。

 public E getLast()  {
    if (size==0)
        throw new NoSuchElementException();

    return header.previous.element;
}

获取元素尾结点,同样的,如果链表中没有元素,会报NoSuchElementException错误。

public E removeFirst() {
    return remove(header.next);
}

删除首结点,其内部是通过下面函数实现的

private E remove(Entry 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;
    }

实现原理就是把要删除结点的前一个结点的下一个节点指向要删除结点的下一个节点,把要输出结点的下一个节点的前结点指向要删除结点的前一个结点,把删除结点的相关成员置空,并返回删除的元素值。

public E removeLast() {
    return remove(header.previous);
    }

删除尾结点,原理如上。

public boolean remove(Object o) {
        if (o==null) {
            for (Entry e = header.next; e != header; e = e.next) {
                if (e.element==null) {
                    remove(e);
                    return true;
                }
            }
        } else {
            for (Entry e = header.next; e != header; e = e.next) {
                if (o.equals(e.element)) {
                    remove(e);
                    return true;
                }
            }
        }
        return false;
    }

删除结点,遍历到对应的结点删除,删除原理如上。

public E remove(int index) {
        return remove(entry(index));
    }

根索引值获取对应Entry,删除原理如上,entry函数的实现在下面会写。

public void addFirst(E e) {
    addBefore(e, header.next);
}

添加首节点,其内部实现原理如下:

private Entry addBefore(E e, Entry entry) {
        Entry newEntry = new Entry(e, entry, entry.previous);
        newEntry.previous.next = newEntry;
        newEntry.next.previous = newEntry;
        size++;
        modCount++;
        return newEntry;
    }

首先新建一个要添加的Entry,通过Entry的含参构造函数指定新Entry的next和prev结点,之后修改使新节点的prev结点的next结点指向自己,使新节点的next结点的prev结点指向自己,并返回新节点。

public void addLast(E e) {
    addBefore(e, header);
}

添加尾结点,原理如上。

public boolean add(E e) {
    addBefore(e, header);
        return true;
    }

添加结点,默认也是添加尾结点,原理如上。

public boolean contains(Object o) {
        return indexOf(o) != -1;
 }

其实现原理如下函数:

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;
}

就是从首节点开始向后遍历,返回对应索引值,找不到则返回-1.

 public E get(int index) {
        return entry(index).element;
 }

获取指定索引元素,实现原理如下函数:

 private Entry entry(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("Index: "+index+
                                                ", Size: "+size);
        Entry 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 E set(int index, E element) {
        Entry e = entry(index);
        E oldVal = e.element;
        e.element = element;
        return oldVal;
    }

先通过索引获取对应Entry,再修改元素值,并返回老元素值。

public void add(int index, E element) {
addBefore(element, (index==size ? header : entry(index)));
}

也是先根据索引值获取对应Entry,并将元素添加到该Entry前。

 public E peek() {
        if (size==0)
            return null;
        return getFirst();
    }

获取首元素,与getFirst()的区别是,如果当前链表中没有元素,则返回null,而getFirst()会报错。

 public E element() {
        return getFirst();
    }

与getFirst()相同

public E poll() {
        if (size==0)
            return null;
        return removeFirst();
    }

删除首元素,与removeFirst()的区别是,如果当前链表中没有元素,则返回null,而removeFirst会报错。

public E remove() {
        return removeFirst();
    }

public boolean offer(E e) {
        return add(e);
    }

 public boolean offerFirst(E e) {
        addFirst(e);
        return true;
    }

public boolean offerLast(E e) {
        addLast(e);
        return true;
    }

public E peekFirst() {
        if (size==0)
            return null;
        return getFirst();
    }

public E peekLast() {
        if (size==0)
            return null;
        return getLast();
    }

public E pollFirst() {
        if (size==0)
            return null;
        return removeFirst();
    }
public E pollLast() {
        if (size==0)
            return null;
        return removeLast();
    }

public void push(E e) {
        addFirst(e);
    }

public E pop() {
        return removeFirst();
    }

这些函数都很简单,都是复用之前的实现,就不一一说明了。

LinkedList(jdk1.7和jdk1.8实现是相同的无区别)

未完待续、、

你可能感兴趣的:(Java)