美文网首页JAVA学习文集程序员
如果现在还不懂LinkedList的原理,赶快收藏这篇文章

如果现在还不懂LinkedList的原理,赶快收藏这篇文章

作者: 小燃儿 | 来源:发表于2020-07-18 12:14 被阅读0次

    01 原理

    LinkedList底层采用双向链表实现。与ArrayList不同,链表不需要扩容,除此之外还会有以下特点。

    02 特点

    1. 非连续的内存,因此不支持随机访问,只能通过节点持有的指针,依次向后(向前)查找就安排,查找的复杂度高。
    image
    1. 插入操作性能好。只需要插入位置的前后节点的引用指向该节点即可。
    image
    1. 删除性能好,与插入类似,将删除节点前后节点的引用互相指向即可。
    image

    03 源码

    最后从源码里具体分析一下,LinkedList中的添加(add),查找(get),删除(remove),插入(add)

    添加(add):

     public boolean add(E e) {
            linkLast(e); // 添加节点到末尾
            return true;
        }
    
     void linkLast(E e) {
            final Node<E> l = last; // 尾节点
            final Node<E> newNode = new Node<>(l, e, null); // 创建e的节点,其中prev指针指向尾部节点,next为空
            last = newNode; // 将尾节点修改为添加的节点
            if (l == null)
                first = newNode; // 没有尾节点,则该节点也是头节点
            else
                l.next = newNode; // 旧的尾节点 next指针指向新添加的节点
            size++; // 数据大小 + 1
            modCount++;
        }
    

    查找(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;
            }
        }
    

    插入(add):

    public void add(int index, E element) {
            checkPositionIndex(index);
    
            if (index == size)
                linkLast(element);  // 添加节点到链表末尾,与添加逻辑一致
            else
                linkBefore(element, node(index)); // 查找下标指向的节点,插入新节点
        }
    
    void linkBefore(E e, Node<E> succ) { // e:插入节点,succ:插入位置上的节点
            // assert succ != null;
            final Node<E> pred = succ.prev;
            final Node<E> newNode = new Node<>(pred, e, succ); // 创建插入e的节点,其中prev指针指向succ的前继节    
                                                                                     //  点,next指向succ节点
            succ.prev = newNode;
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode; // succ前继节点的next指针指向插入的节点
            size++;
            modCount++;
        }
    

    删除(remove):

    public E remove(int index) {
            checkElementIndex(index);
            return unlink(node(index)); // 删除
        }
    
    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; // 前继节点的next指针指向后继节点
                x.prev = null; // 删除节点的pre指针置为null
            }
    
            if (next == null) { // 插入位置为尾部
                last = prev;
            } else {
                next.prev = prev; // 后继节点的prev指针指向前继节点
                x.next = null; // 删除节点的next指针置为null
            }
    
            x.item = null; // 删除节点的指置为null,让GC可以回收
            size--;
            modCount++;
            return element;
        }
    

    相关文章

      网友评论

        本文标题:如果现在还不懂LinkedList的原理,赶快收藏这篇文章

        本文链接:https://www.haomeiwen.com/subject/lgbxkktx.html