Java集合之LinkedList源码解析

LinkedList

非线程安全的可重复元素顺序列表

继承AbstractSequentialList;其父类为AbstractList骨架实现该类要求子类必须重写listIterator(int index)方法(AbstractList已提供骨架实现

实现了Cloneable,实现浅克隆;

实现了序列化接口,并自定义了readObject、writeObject方法

实现了Deque接口,提供了双端队列的相关方法,可以做为双端队列或栈使用


JDK1.6版本的LinkedList顺序列表采用双向循环链表实现,存在固定的header链表头元素,下一个为首元素,上一个为末元素

JDK1.7版本的LinkedList顺序列表采用双向链表实现,分别定义了first、last元素,以便进行正向及反向查找

该数据结构,进行下标查询操作时需要从首元素或末元素开始逐个查找(算法时间复杂度O(n));

插入、删除到指定位置时,需要先进行位置查找到指定位置元素,然后进行新增及位置链接设置操作(算法时间复杂度O(n))

仅在较前位置插入删除会较ArrayList快,由于ArrayList采用了数组快速移动方法,在数据量大时比ArrayList插入、删除慢


重点方法:

1、数据结构及构造器

(1)元素定义

JDK1.6

    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;
        }
    }
JDK1.8(1.7将类名调整为Node以便与map的Entry区分,构造顺序进行了调整)
    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;
        }
    }
(2)首尾节点记录及构造方法,与ArrayList一样,除了无参构造外也提供了拷贝构造器

JDK1.6,只定义空的header头节点,上一个是列表最后元素,下一个是列表首个元素

    private transient Entry<E> header = new Entry<E>(null, null, null);//链表头

    public LinkedList() {//无参构造
        header.next = header.previous = header;//将链表头的next、previous都指向自己
    }

    public LinkedList(Collection<? extends E> c) {//拷贝构造器,支持任意集合;支持子类
        this();//调用无参构造,先建立链表头
        addAll(c);//然后将集合中的元素新增进来
    }

    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

    public boolean addAll(int index, Collection<? extends E> c) {//将集合中元素按原顺序批量插入到指定位置
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index+
                                                ", Size: "+size);
        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew==0)
            return false;
        modCount++;

        Entry<E> successor = (index==size ? header : entry(index));//确认插入的后置元素,如果在末端插入则为链表头,否则需取得指定位置的元素
        Entry<E> predecessor = successor.previous;//根据后置元素,确认插入的前置元素
        for (int i=0; i<numNew; i++) {//循环数组
            Entry<E> e = new Entry<E>((E)a[i], successor, predecessor);//新建元素,next指向后置元素,previous指向前置元素(除最后一个外,后置元素不需要设置,保证previous对即可)
            predecessor.next = e;//前置元素的next指向新建元素(从第2次循环开始,完成了上一个新增元素的next设置)
            predecessor = e;//将新建元素做为下一个循环的前置元素
        }
        successor.previous = predecessor;//后置元素的previous设置为最后一个数组对应的新建元素

        size += numNew;//增加列表长度
        return true;
    }
JDK1.8(1.7将数据结构调整为首末两个双向链表,首元素的上一个为null,末元素的下一个为null)

    transient Node<E> first;//首元素
    transient Node<E> last;//末元素
    public LinkedList() {
    }
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }
(3)插入操作,删除也类似

JDK1.6

    public void addFirst(E e) {//实现双端队列接口,插入首元素
        addBefore(e, header.next);
    }
    public void addLast(E e) {//实现双端队列接口,插入末元素
        addBefore(e, header);
    }
    private Entry<E> addBefore(E e, Entry<E> entry) {//在前面插入元素
        Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);//新建元素
        newEntry.previous.next = newEntry;//将上一个的next指向新增元素
        newEntry.next.previous = newEntry;//将下一个的previous指向新增元素
        size++;//列表长度增加
        modCount++;
        return newEntry;
    }
JDK1.8

    public void addFirst(E e) {
        linkFirst(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;//原首元素的prev指向新增元素
        size++;
        modCount++;
    }
    public void addLast(E e) {
        linkLast(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;//原末元素的next指向新增元素
        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;//将某个元素的prev设置为新增元素
        if (pred == null)//如果某个元素的原始上个元素为空,则为队首,将首元素设置为新增元素
            first = newNode;
        else
            pred.next = newNode;//上个元素next指向新增元素
        size++;
        modCount++;
    }
(4)查找元素

JDK1.6

    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;
    }
JDK1.8

    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;
        }
    }
2、迭代器模式

LinkedList使用内部类实现了具体的fast-fail迭代器,并且保持iterator与listIterator创建相同的ListItr迭代器。fail-fast 迭代器,这意味着它假设线程在集合内容中进行迭代时,集合不会更改它的内容。如果 fail-fast 迭代器检测到在迭代过程中进行了更改操作(链表结构的更改),那么会抛出 ConcurrentModificationException 。

JDK1.6版本(1.8与此类似,只是数据结构不同导致变化,不做列举)

    public ListIterator<E> listIterator(int index) {//按父类要求重写listIterator
        return new ListItr(index);
    }

    private class ListItr implements ListIterator<E> {//内部类实现具体的迭代器
        private Entry<E> lastReturned = header;//最近返回元素;默认为链表头,next、previous方法会变动该元素,remove、add方法调用后重置为链表头
        private Entry<E> next;//下一个元素
        private int nextIndex;//下一个位置
        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;//next移动到下一元素
            nextIndex++;//下一个位置更新
            return lastReturned.element;
        }
    
        public boolean hasPrevious() {
            return nextIndex != 0;//默认0,第0个元素没有上一元素
        }
    
        public E previous() {//上一个元素
            if (nextIndex == 0)
                throw new NoSuchElementException();
    
            lastReturned = next = next.previous;//最近返回元素设置为上一元素,next移动到上一元素
            nextIndex--;//下一个位置更新
            checkForComodification();//其他都先检查,应当写到前面,1.7已修正
            return lastReturned.element;
        }
    
        public int nextIndex() {
            return nextIndex;
        }
    
        public int previousIndex() {
            return nextIndex-1;
        }
    
        public void remove() {//删除最近返回元素
            checkForComodification();
            Entry<E> lastNext = lastReturned.next;
            try {
                LinkedList.this.remove(lastReturned);//清空元素
            } catch (NoSuchElementException e) {
                throw new IllegalStateException();
            }
            if (next==lastReturned)
                next = lastNext;//如果next被删除,重置next
            else
                nextIndex--;//否则减少index(此情况只有上一次调用next()发生,目前位置肯定在lastReturned后面)
            lastReturned = header;//重置最近返回元素为链表头
            expectedModCount++;
        }
    
        public void set(E e) {//替换最近返回元素
            if (lastReturned == header)//链表头不允许替换
                throw new IllegalStateException();
            checkForComodification();
            lastReturned.element = e;//set方法由于不改变链表结构,不更新expectedModCount/modCount,但仍需check
        }
    
        public void add(E e) {//在下个元素前方增加元素
            checkForComodification();
            lastReturned = header;
            addBefore(e, next);
            nextIndex++;
            expectedModCount++;
        }
    
        final void checkForComodification() {//fast-fail判断,失败抛异常
            if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        }
    }
3、几个双端队列方法及区别

(1)addFirst/offerFirtst;addLast/offerLast,均为插入列表的首末元素,add方法没有返回值,offer方法返回插入成功失败

(2)removeFirst/pollFirst;removeLast/pollLast,均为删除列表的首末元素,并且都返回删除元素数据,但空列表时remove抛异常,poll返回null

(3)getFirst/peekFirst;getLast/peekLast,均为取得列表的首末元素,并且都返回删除元素数据,但空列表时get抛异常,peek返回null

(4)push调用的addFirst;pop调用的removeFirst

4、实现双端队列特殊的反向迭代器

JDK1.6与JDK1.8一致

    public Iterator<E> descendingIterator() {
        return new DescendingIterator();
    }
    private class DescendingIterator implements Iterator<E> {//内部类建立反向迭代器
        private final ListItr itr = new ListItr(size());//从最后元素开始
        public boolean hasNext() {
            return itr.hasPrevious();//反向处理
        }
        public E next() {
            return itr.previous();//反向处理
        }
        public void remove() {
            itr.remove();
        }
    }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值