深入理解LinkedList

来源:互联网 发布:唯美画面知乎 编辑:程序博客网 时间:2024/06/07 05:32

说明

本文是基于JDK7对LinkedList进行总结。通过阅读源码,对LinkedList的实现原理,特点等进行理解和掌握。

正文

LinkedList的特点

      与ArrayList不同的是,LinkedList是基于双向链表实现的,适合增删多查找少的场景;相同的是都允许有空值(null),允许有重复值,插入数据是有序的,都是非线程安全的。

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

LinkedList继承了AbstractSequentialList类,实现了List, Deque, Cloneable, java.io.Serializable接口。
除了可以当作链表操作外,还可以当作栈、队列或双端队列使用。

节点类Node

 private static class Node<E> {        E item;//节点的值        Node<E> next;//指向前一节点        Node<E> prev;//指向后一节点        Node(Node<E> prev, E element, Node<E> next) {            this.item = element;            this.next = next;            this.prev = prev;        }    }

LinkedList的成员变量

transient int size = 0;//链表中节点的个数transient Node<E> first;//首节点transient Node<E> last;//尾节点

LinkedList的构造函数

缺省构造函数

public LinkedList() {  }//方法为空

指定一个Collection对象作为参数的构造函数,元素的顺序有这个对象迭代器返回的顺序决定

 public LinkedList(Collection<? extends E> c) {        this();        addAll(c);    }

链表中的插入

LinkedList的linkFirst(E e)方法

链头插入一个元素

private void linkFirst(E e) {        final Node<E> f = first;        final Node<E> newNode = new Node<>(null, e, f);        first = newNode;        if (f == null)//如果首节点为空            last = newNode;//将新节点作为尾节点        else            f.prev = newNode;//不为空 只修改第一个节点的前驱就可以        size++;//节点个数加1        modCount++;//修改次数加1    }

LinkedList的linkLast(E e)方法

链尾添加一个元素

void linkLast(E e) {        final Node<E> l = last;        final Node<E> newNode = new Node<>(l, e, null);        last = newNode;        if (l == null)//如果尾部为空              first = newNode;//将新节点作为首节点        else            l.next = newNode;//不为空 直接改变最后一个元素的后继        size++;        modCount++;    }

LinkedList的linkBefore(E e, Node succ)方法

某个节点前插入一个元素

void linkBefore(E e, Node<E> succ) {        // assert succ != null;        final Node<E> pred = succ.prev;//节点的前驱节点        final Node<E> newNode = new Node<>(pred, e, succ);        succ.prev = newNode;//将节点的前驱改为新节点        if (pred == null)//若原来前驱为空            first = newNode;//新节点作为首节点        else            pred.next = newNode;//不为空  原来前驱节点的后继节点改为新节点        size++;//节点个数加1        modCount++;    }

LinkedList的add方法

 //在链头添加一个元素 public void addFirst(E e) {        linkFirst(e);//在链尾添加一个元素public void addLast(E e) {        linkLast(e);    }//一般这个方法最常用public boolean add(E e) { //此方法会返回一个boolean类型的值         linkLast(e);//是在链尾进行添加        return true;    }//添加一个集合中的所有元素public boolean addAll(Collection<? extends E> c) {        return addAll(size, c);//调用addAll(int index, Collection<? extends E> c)方法,        //index等于size,也就是说在链尾进行添加    }//在某个节点前添加一个集合中的所有元素    public boolean addAll(int index, Collection<? extends E> c) {        checkPositionIndex(index);//首先判断是否越界        Object[] a = c.toArray();        int numNew = a.length;        if (numNew == 0)            return false;        Node<E> pred, succ;        if (index == size) {            succ = null;            pred = last;        } else {            succ = node(index);//将节点作为新节点的后继            pred = succ.prev;//找出节点的前驱        }        for (Object o : a) {            @SuppressWarnings("unchecked") E e = (E) o;            Node<E> newNode = new Node<>(pred, e, null);            if (pred == null)                first = newNode;            else                pred.next = newNode;//节点的前驱节点的后继节点改为新节点            pred = newNode;//新节点作为前驱节点        }        if (succ == null) {            last = pred;        } else {            pred.next = succ;//新节点的后继节点就是该节点            succ.prev = pred;        }        size += numNew;        modCount++;        return true;    }//在某个位置添加一个元素public void add(int index, E element) {        checkPositionIndex(index);        if (index == size)//index==size  在链尾进行添加            linkLast(element);        else            linkBefore(element, node(index));//在index前插入元素    }

LinkedList的get方法

//得到链头元素public E getFirst() {        final Node<E> f = first;        if (f == null)            throw new NoSuchElementException();        return f.item;    }//得到链尾元素public E getLast() {        final Node<E> l = last;        if (l == null)            throw new NoSuchElementException();        return l.item;    }//得到某个位置的元素public E getLast() {        final Node<E> l = last;        if (l == null)            throw new NoSuchElementException();        return l.item;    }

链表中的删除

在看remove方法前先看unlink方法

LinkedList的unlink方法

//删除链头元素private E unlinkFirst(Node<E> f) {        // assert f == first && f != null;        final E element = f.item;        final Node<E> next = f.next;        f.item = null;        f.next = null; // help GC 在这可以看到  删除一个节点 将该节所有属性置为null 让垃圾回收器回收        first = next;        if (next == null)            last = null;        else            next.prev = null;        size--;//节点个数减1        modCount++;        return element;//返回节点的值    }//删除链尾元素 private E unlinkLast(Node<E> l) {        // assert l == last && l != null;        final E element = l.item;        final Node<E> prev = l.prev;        l.item = null;        l.prev = null; // help GC        last = prev;        if (prev == null)            first = null;        else            prev.next = null;        size--;        modCount++;        return element;    }//在链表中删除某个指定的节点E unlink(Node<E> x) {        // assert x != null;        final E element = x.item;//该节点的值        final Node<E> next = x.next;//该节点的后继节点        final Node<E> prev = x.prev;//该节点的前驱节点        if (prev == null) {//若前驱节点为空  则将后继节点置为头节点            first = next;        } else {            prev.next = next;            x.prev = null;        }        if (next == null) {//若后继节点为空  则将前驱节点置为尾节点            last = prev;        } else {            next.prev = prev;            x.next = null;        }        x.item = null;//将值置为null        size--;//个数减1        modCount++;        return element;//返回值    }

LinkedList的remove方法

remove方法中都是调用unlink方法

//删除并返回链头元素public E removeFirst() {        final Node<E> f = first;        if (f == null)            throw new NoSuchElementException();        return unlinkFirst(f);    }//删除并返回链尾元素public E removeLast() {        final Node<E> l = last;        if (l == null)            throw new NoSuchElementException();        return unlinkLast(l);    }//删除某个指定的元素 public boolean remove(Object o) {//此方法不返回元素的值  只返回boolean类型的值        if (o == null) {            for (Node<E> x = first; x != null; x = x.next) {                if (x.item == null) {                    unlink(x);                    return true;                }            }        } else {            for (Node<E> x = first; x != null; x = x.next) {                if (o.equals(x.item)) {                    unlink(x);                    return true;                }            }        }        return false;    }//删除并返回指定位置的元素public E remove(int index) {        checkElementIndex(index);//要检查指定位置是否越界        return unlink(node(index));    }

LinkedList的clear()方法

public void clear() {        // Clearing all of the links between nodes is "unnecessary", but:        // - helps a generational GC if the discarded nodes inhabit        //   more than one generation        // - is sure to free memory even if there is a reachable Iterator        //清除节点之间的链接是“不必要的”,        //但是为了确保在有可到达的迭代器时也可以释放内存,有助于GC        for (Node<E> x = first; x != null; ) {            Node<E> next = x.next;            x.item = null;            x.next = null;            x.prev = null;            x = next;        }        first = last = null;//将所有节点置为null        size = 0;//个数置为0        modCount++;    }

LinkedList的indexOf(Object o)方法

该方法返回指定元素在链表中第一次出现的位置,没有该元素则返回-1

 public int indexOf(Object o) {        int index = 0;        if (o == null) {            for (Node<E> x = first; x != null; x = x.next) {                if (x.item == null)                    return index;                index++;            }        } else {            for (Node<E> x = first; x != null; x = x.next) {                if (o.equals(x.item))                    return index;                index++;            }        }        return -1;    }

LinkedList作为队列时的操作方法

peek()方法

public E peek() {        final Node<E> f = first;        return (f == null) ? null : f.item;//返回链头元素的值    }

element()方法

public E element() {        return getFirst();//返回链头元素的值    }

poll()方法

public E poll() {        final Node<E> f = first;        return (f == null) ? null : unlinkFirst(f);//调用unlinkFirst方法,删除并返回链头元素的值    }

remove()方法

 public E remove() {        return removeFirst();//删除并返回链头元素的值    }

offer()方法

    public boolean offer(E e) {        return add(e);//在链尾插入元素    }

push(E e)方法

public void push(E e) {        addFirst(e);//在链头插入元素    }

pop()方法

    public E pop() {        return removeFirst();//删除并返回链头元素    }

LinkedList的toArray()方法

该方法将LinkedList中的元素转换成一个数组 该数组类型为Object

public Object[] toArray() {        Object[] result = new Object[size];        int i = 0;        for (Node<E> x = first; x != null; x = x.next)            result[i++] = x.item;        return result;    }

LinkedList的toArray(T[] a)方法

该方法将LinkedList中的元素全部放到一个数组中并返回数组,该数组的类型为参数的指定类型

public <T> T[] toArray(T[] a) {        if (a.length < size)            a = (T[])java.lang.reflect.Array.newInstance(                                a.getClass().getComponentType(), size);                 //如果数组的长度小于元素的个数,就使用反射实例化一个长度为size的新数组        int i = 0;        Object[] result = a;        for (Node<E> x = first; x != null; x = x.next)            result[i++] = x.item;        if (a.length > size)//若数组长度大于元素个数,将数组size位置置为null            a[size] = null;        return a;    }