LinkedList

来源:互联网 发布:《大数据思维与决策》 编辑:程序博客网 时间:2024/06/16 04:18

1、LinkedList简介

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
LinkedList 实现 List 接口,能对它进行队列操作。
LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
LinkedList 是非同步的。

1.2 构造函数

// 默认构造函数LinkedList()// 创建一个LinkedList,保护Collection中的全部元素。LinkedList(Collection<? extends E> collection)

1.3 API

boolean add(E e)将指定的元素追加到此列表的末尾。void    add(int index, E element)在此列表中的指定位置插入指定的元素。boolean addAll(Collection<? extends E> c)按照指定集合的迭代器返回的顺序将指定集合中的所有元素追加到此列表的末尾。boolean addAll(int index, Collection<? extends E> c)将指定集合中的所有元素插入到此列表中,从指定的位置开始。void    addFirst(E e)在该列表开头插入指定的元素。void    addLast(E e)将指定的元素追加到此列表的末尾。void    clear()从列表中删除所有元素。Object  clone()返回此 LinkedList的浅版本。boolean contains(Object o)如果此列表包含指定的元素,则返回 true 。Iterator<E> descendingIterator()以相反的顺序返回此deque中的元素的迭代器。E   element()检索但不删除此列表的头(第一个元素)。E   get(int index)返回此列表中指定位置的元素。E   getFirst()返回此列表中的第一个元素。E   getLast()返回此列表中的最后一个元素。int indexOf(Object o)返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。int lastIndexOf(Object o)返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。ListIterator<E> listIterator(int index)从列表中的指定位置开始,返回此列表中元素的列表迭代器(按适当的顺序)。boolean offer(E e)将指定的元素添加为此列表的尾部(最后一个元素)。boolean offerFirst(E e)在此列表的前面插入指定的元素。boolean offerLast(E e)在该列表的末尾插入指定的元素。E   peek()检索但不删除此列表的头(第一个元素)。E   peekFirst()检索但不删除此列表的第一个元素,如果此列表为空,则返回 null 。E   peekLast()检索但不删除此列表的最后一个元素,如果此列表为空,则返回 null 。E   poll()检索并删除此列表的头(第一个元素)。E   pollFirst()检索并删除此列表的第一个元素,如果此列表为空,则返回 null 。E   pollLast()检索并删除此列表的最后一个元素,如果此列表为空,则返回 null 。E   pop()从此列表表示的堆栈中弹出一个元素。void    push(E e)将元素推送到由此列表表示的堆栈上。E   remove()检索并删除此列表的头(第一个元素)。E   remove(int index)删除该列表中指定位置的元素。boolean remove(Object o)从列表中删除指定元素的第一个出现(如果存在)。E   removeFirst()从此列表中删除并返回第一个元素。boolean removeFirstOccurrence(Object o)删除此列表中指定元素的第一个出现(从头到尾遍历列表时)。E   removeLast()从此列表中删除并返回最后一个元素。boolean removeLastOccurrence(Object o)删除此列表中指定元素的最后一次出现(从头到尾遍历列表时)。E   set(int index, E element)用指定的元素替换此列表中指定位置的元素。int size()返回此列表中的元素数。Spliterator<E>  spliterator()在此列表中的元素上创建late-binding和故障快速 Spliterator 。Object[]    toArray()以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。<T> T[] toArray(T[] a)以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。

2、数据结构

2.1 继承关系

java.lang.Object   ↳     java.util.AbstractCollection<E>         ↳     java.util.AbstractList<E>               ↳     java.util.AbstractSequentialList<E>                     ↳     java.util.LinkedList<E>public class LinkedList<E>    extends AbstractSequentialList<E>    implements List<E>, Deque<E>, Cloneable, java.io.Serializable {}

2.2 类图

这里写图片描述

2.3 源代码

public class LinkedList<E>    extends AbstractSequentialList<E>    implements List<E>, Deque<E>, Cloneable, java.io.Serializable{       //链表长度    transient int size = 0;    transient Node<E> first;    transient Node<E> last;    //默认构造    public LinkedList() {    }    public LinkedList(Collection<? extends E> c) {        this();        addAll(c);    }    //节点类    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;        }    }    //将元素插入链表头    private void linkFirst(E e) {        //保存首元素对象        final Node<E> f = first;        //构造新对象newNode,并使newNode的next指向first。        final Node<E> newNode = new Node<>(null, e, f);        //将first指向newNode        first = newNode;        //如果原本first为null 表示一开始是空链表,插入一个之后,此时链表中只有一个元素        if (f == null)            last = newNode;        else            //将原来first的前置对象指向newNode,形成双向链表            f.prev = newNode;        size++;        //支持fast-failed        modCount++;    }    //插入结尾    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++;    }    //插入指定元素之前    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++;        modCount++;    }    //移除元素    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;        size--;        modCount++;        return element;    }    //获取首元素    public E getFirst() {        final Node<E> f = first;        if (f == null)            throw new NoSuchElementException();        return f.item;    }    //开放的接口 插入头元素    public void addFirst(E e) {        linkFirst(e);    }    //移除操作    public boolean remove(Object o) {        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 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        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;        size = 0;        modCount++;    }    //offer只是对add的一层包装    public boolean offer(E e) {        return add(e);    }    //检出    public E pollLast() {        final Node<E> l = last;        return (l == null) ? null : unlinkLast(l);    }    //push pop都是对首元素进行操作    public void push(E e) {        addFirst(e);    }    public E pop() {        return removeFirst();    }    //获取指定位置的元素    Node<E> node(int index) {        // assert isElementIndex(index);        if (index < (size >> 1)) {            Node<E> x = first;            for (int i = 0; i < index; i++)                x = x.next;            return x;        } else {            Node<E> x = last;            for (int i = size - 1; i > index; i--)                x = x.prev;            return x;        }    }

LinkedList是一个双端链表结构
可以当做链表栈:pop()、push(E e)
也可以当做双端队列:poll()、offer(E e)、pollFirst()、pollLast()
线程不安全
支持fail-fast

2.4 遍历

public class Test{    public static void main(String[] args) {        // 通过Iterator遍历LinkedList        forIteratorTrav(getLinkedList()) ;        // 通过快速随机访问遍历LinkedList        forTrav(getLinkedList()) ;        // 通过for循环的变种来访问遍历LinkedList        foreachTrav(getLinkedList()) ;        // 通过PollFirst()遍历LinkedList        pollFirstTrav(getLinkedList()) ;        // 通过PollLast()遍历LinkedList        pollLasttTrav(getLinkedList()) ;        // 通过removeFirst()遍历LinkedList        removeFirstTrav(getLinkedList()) ;        // 通过removeLast()遍历LinkedList        removeLastTrav(getLinkedList()) ;    }    private static LinkedList getLinkedList() {        LinkedList llist = new LinkedList();        for (int i=0; i<100000; i++)            llist.addLast(i);        return llist;    }    /**     * 通过快迭代器遍历LinkedList     */    private static void forIteratorTrav(LinkedList<Integer> list) {        if (list == null)            return ;        // 记录开始时间        long start = System.currentTimeMillis();        for(Iterator iter = list.iterator(); iter.hasNext();)            iter.next();        // 记录结束时间        long end = System.currentTimeMillis();        long interval = end - start;        System.out.println("forIteratorTrav:" + interval+" ms");    }    /**     * 通过快速随机访问遍历LinkedList     */    private static void forTrav(LinkedList<Integer> list) {        if (list == null)            return ;        // 记录开始时间        long start = System.currentTimeMillis();        int size = list.size();        for (int i=0; i<size; i++) {            list.get(i);        }        // 记录结束时间        long end = System.currentTimeMillis();        long interval = end - start;        System.out.println("forTrav:" + interval+" ms");    }    /**     * 通过另外一种for循环来遍历LinkedList     */    private static void foreachTrav(LinkedList<Integer> list) {        if (list == null)            return ;        // 记录开始时间        long start = System.currentTimeMillis();        for (Integer integ:list)            ;        // 记录结束时间        long end = System.currentTimeMillis();        long interval = end - start;        System.out.println("foreachTrav:" + interval+" ms");    }    /**     * 通过pollFirst()来遍历LinkedList     */    private static void pollFirstTrav(LinkedList<Integer> list) {        if (list == null)            return ;        // 记录开始时间        long start = System.currentTimeMillis();        while(list.pollFirst() != null)            ;        // 记录结束时间        long end = System.currentTimeMillis();        long interval = end - start;        System.out.println("pollFirstTrav:" + interval+" ms");    }    /**     * 通过pollLast()来遍历LinkedList     */    private static void pollLasttTrav(LinkedList<Integer> list) {        if (list == null)            return ;        // 记录开始时间        long start = System.currentTimeMillis();        while(list.pollLast() != null)            ;        // 记录结束时间        long end = System.currentTimeMillis();        long interval = end - start;        System.out.println("pollLasttTrav:" + interval+" ms");    }    /**     * 通过removeFirst()来遍历LinkedList     */    private static void removeFirstTrav(LinkedList<Integer> list) {        if (list == null)            return ;        // 记录开始时间        long start = System.currentTimeMillis();        try {            while(list.removeFirst() != null)                ;        } catch (NoSuchElementException e) {        }        // 记录结束时间        long end = System.currentTimeMillis();        long interval = end - start;        System.out.println("removeFirstTrav:" + interval+" ms");    }    /**     * 通过removeLast()来遍历LinkedList     */    private static void removeLastTrav(LinkedList<Integer> list) {        if (list == null)            return ;        // 记录开始时间        long start = System.currentTimeMillis();        try {            while(list.removeLast() != null)                ;        } catch (NoSuchElementException e) {        }        // 记录结束时间        long end = System.currentTimeMillis();        long interval = end - start;        System.out.println("removeLastTrav:" + interval+" ms");    }}
forIteratorTrav:6 msforTrav:6518 msforeachTrav:3 mspollFirstTrav:2 mspollLasttTrav:2 msremoveFirstTrav:2 msremoveLastTrav:2 ms

遍历除了for循环,其他都差不多。

2.5 注意事项

LinkedList遍历避免使用for循环

for (int i=0; i<size; i++) {    list.get(i);}

list的get源码:

    public E get(int index) {        checkElementIndex(index);        return node(index).item;    }    Node<E> node(int index) {        // assert isElementIndex(index);        if (index < (size >> 1)) {            Node<E> x = first;            for (int i = 0; i < index; i++)                x = x.next;            return x;        } else {            Node<E> x = last;            for (int i = size - 1; i > index; i--)                x = x.prev;            return x;        }    }

get方法会进行优化,如果小于size/2 从前端遍历,否则从后端遍历

所以如果遍历一个长度为n的LinkedList,需要遍历
i<n/2时 1+2+…n/2-1次 = n/2 * (n/2)/2
所以总共需要(n/2*(n/2))/2*2 = n2/4 (为了简便,算的不是太准确,但也差不太多)

总共需要额外遍历n2/4n次。如果n=1000,则额外遍历24000次

原创粉丝点击