LinkedList删除结点源码分析

Posted 似水流年,是谁苍白了等待

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LinkedList删除结点源码分析相关的知识,希望对你有一定的参考价值。

目录

 

前言

那么LinkedList用来存储数据,那么跟ArrayList有什么区别?

LinkedList删除结点是怎么样删除的?

1、首先了解LinkedList类声明的变量有哪些

2、内部类Node说明

3.LinkedList.remove() 方法;默认删除第一个结点

1)执行removeFirst

2)执行removeFirst

3)执行unlinkFirst(f),    //将f指向的双向链表的第一个结点拿掉

执行过程详解


前言

在学习LinkedList之前,我们先需要了解LinkeList是什么?以及它是怎么样实现的等多个知识点;

LinkedList是一种常见的基础数据结构,基于链表,也是一种线性表,但是它的存储并不会按线性的顺序存储数据,在数据结构自考课本中学过,它的存储地址是离散的,可以存在位置不相邻的位置,而且在每一个节点里存到下一个节点的地址。

那么LinkedList用来存储数据,那么跟ArrayList有什么区别?

  • linkedlist和arraylist不同,删除或增加元素时,其后边的元素都不需要跟着移动,因为他的地址是可以不连续的。只需要引用前后节点的指针就行。
  • linkedlist删除和增加的效率比较高,LinkedList是基于双向链表存储的,当查询对应index位置的数据时,会先计算链表总长度一半的值,判读index是在这个值的左边还是右边,然后决定从头结点还是从尾结点开始遍历;

如图,可以看看源码

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对内存的占用也是比较大的,毕竟每个Node都维护着前后指向地址的节点,数据量大的话会占用不少内存空间。

因为每存一个元素就需要一个节点,所以这样下来当数据量大的时候node节点也非常大,会占用更多的内存。

LinkedList删除结点是怎么样删除的?

public class Test {
    public static void main(String[] args) {
       
        LinkedList linkedList = new LinkedList();

        linkedList.remove(1);
        System.out.println("linkedList"+linkedList);
    }
}

根据此代码段分析它删除实现

1、首先了解LinkedList类声明的变量有哪些

全部成员变量说明

//用于标识链表的长度
  transient int size = 0;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    //指向链表的头
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    //指向链表的尾
    transient Node<E> last;

2、内部类Node<E>说明

private static class Node<E> {
        E item;     //item用于保存数据
        Node<E> next;   //next用于指向当前节点的下一个节点
        Node<E> prev;   //prev用于指向当前节点的前一个节点

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

3.LinkedList.remove() 方法;默认删除第一个结点

1)执行removeFirst

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

2)执行removeFirst

public E removeFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return unlinkFirst(f);
}

3)执行unlinkFirst(f),    //将f指向的双向链表的第一个结点拿掉

private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;
        //获取到将要删除的元素
        final E element = f.item;
        //将next引用指向下一个节点
        final Node<E> next = f.next;
        //将删除的元素置空,垃圾回收器会自动清除内容
        f.item = null;
        //将删除的内容
        f.next = null; // help GC
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
    }

执行过程详解

  • 获取到将要删除的元素(内容)
  • 将next引用指向下一个节点
  • 当前的元素值为空,意味着删除了传进去的那个节点
  • 删除需要删除的节点和下一个结点的引用,让垃圾回收器认为它是个垃圾。
  • 将原先的first指向下一个结点
  • 判断next是否为空,这里返回false,因此需要走next.prev=null也就是将下一个结点的前驱删掉,此时f结点已经成为一个单独的节点,没有任务引用指向他,就成为了垃圾。
  • 链表减一
  • 修改记录加一
  • 返回删除的元素

以上是关于LinkedList删除结点源码分析的主要内容,如果未能解决你的问题,请参考以下文章

JDK源码分析-LinkedList

LinkedList源码分析--jdk1.8

JDKJDK源码分析-LinkedList

LinkedList源码分析

LinkedList 源码分析与总结

LinkedList源码分析