Java LinkedList的实现原理图文详解

 更新时间:2019年01月11日 14:29:24   作者:qq_43193797  
今天小编就为大家分享一篇关于Java LinkedList的实现原理图文详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

一、概述

先来看看源码中的这一段注释,我们先尝试从中提取一些信息:

Doubly-linked list implementation of the List and Deque interfaces. Implements all optional list operations, and permits all elements (including null).All of the operations perform as could be expected for a doubly-linked list. Operations that index into the list will traverse the list from the beginning or the end, whichever is closer to the specified index.Note that this implementation is not synchronized. If multiple threads access a linked list concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list.

从这段注释中,我们可以得知 LinkedList 是通过一个双向链表来实现的,它允许插入所有元素,包括 null,同时,它是线程不同步的。如果对双向链表这个数据结构很熟悉的话,学习LinkedList 就没什么难度了。下面是双向链表的结构:

双向链表每个结点除了数据域之外,还有一个前指针和后指针,分别指向前驱结点和后继结点(如果有前驱/后继的话)。另外,双向链表还有一个 first 指针,指向头节点,和 last 指针,指向尾节点。

二、属性

接下来看一下 LinkedList 中的属性:

//链表的节点个数
transient int size = 0;
//指向头节点的指针
transient Node<E> first;
//指向尾节点的指针
transient Node<E> last;

LinkedList 的属性非常少,就只有这些。通过这三个属性,其实我们大概也可以猜测出它是怎么实现的了。

三、方法

1、结点结构

Node 是在 LinkedList 里定义的一个静态内部类,它表示链表每个节点的结构,包括一个数据域 item,一个后置指针 next,一个前置指针 prev。

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、添加元素

对于链表这种数据结构来说,添加元素的操作无非就是在表头/表尾插入元素,又或者在指定位置插入元素。因为 LinkedList 有头指针和尾指针,所以在表头或表尾进行插入元素只需要 O(1) 的时间,而在指定位置插入元素则需要先遍历一下链表,所以复杂度为 O(n)。

在表头添加元素的过程如下:

当向表头插入一个节点时,很显然当前节点的前驱一定为 null,而后继结点是 first 指针指向的节点,当然还要修改 first 指针指向新的头节点。除此之外,原来的头节点变成了第二个节点,所以还要修改原来头节点的前驱指针,使它指向表头节点,源码的实现如下:

private void linkFirst(E e) {
 final Node<E> f = first;
 //当前节点的前驱指向 null,后继指针原来的头节点
 final Node<E> newNode = new Node<>(null, e, f);
 //头指针指向新的头节点
 first = newNode;
 //如果原来有头节点,则更新原来节点的前驱指针,否则更新尾指针
 if (f == null)
 last = newNode;
 else
 f.prev = newNode;
 size++;
 modCount++;
}

在表尾添加元素跟在表头添加元素大同小异,如图所示

当向表尾插入一个节点时,很显然当前节点的后继一定为 null,而前驱结点是 last指针指向的节点,然后还要修改 last 指针指向新的尾节点。此外,还要修改原来尾节点的后继指针,使它指向新的尾节点,源码的实现如下:

void linkLast(E e) {
 final Node<E> l = last;
 //当前节点的前驱指向尾节点,后继指向 null
 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++;
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。如果你想了解更多相关内容请查看下面相关链接

相关文章

  • httpclient evict操作源码解读

    httpclient evict操作源码解读

    这篇文章主要为大家介绍了httpclient evict操作源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • IDEA 程序包不存在,找不到符号但是明明存在对应的jar包(问题分析及解决方案)

    IDEA 程序包不存在,找不到符号但是明明存在对应的jar包(问题分析及解决方案)

    这篇文章主要介绍了IDEA 程序包不存在,找不到符号但是明明存在对应的jar包 的解决方案,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • java二分查找插入法

    java二分查找插入法

    当你需要构建一个大的有序队列,用插入发太慢了,可以先用二分查找法,找到在队列要插入的位置,把数后移一下,然后放进去。比较效率,下面是java使用示例,需要的朋友可以参考下
    2014-03-03
  • Java中ThreadLocal 导致内存 OOM 的原因分析

    Java中ThreadLocal 导致内存 OOM 的原因分析

    这篇文章主要介绍了Java中ThreadLocal导致内存OOM的原因分析,文章基于Java的相关内容展开ThreadLocal导致内存OOM的原因分析,需要的小伙v阿布可以参考一下
    2022-05-05
  • java单例模式学习示例

    java单例模式学习示例

    java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种,下面提供了单例模式的示例
    2014-01-01
  • Java的动态代理和静态代理及反射常用API详解

    Java的动态代理和静态代理及反射常用API详解

    这篇文章主要介绍了Java的动态代理和静态代理及反射常用API详解,动态代理是一种在运行时动态生成代理对象的技术,它是一种设计模式,用于在不修改原始对象的情况下,通过代理对象来间接访问原始对象,并在访问前后执行额外的操作,需要的朋友可以参考下
    2024-01-01
  • Java 9 中的模块Module系统

    Java 9 中的模块Module系统

    Java 9 引入的模块是在Java包(package)的基础上又引入的一个新的抽象层,基于package这一点很重要,这里需要强调一下,接下来通过本文给大家介绍Java 9 中的模块Module系统,感兴趣的朋友一起看看吧
    2022-03-03
  • Mybatis/Mybatis-Plus驼峰式命名映射的实现

    Mybatis/Mybatis-Plus驼峰式命名映射的实现

    本文主要介绍了Mybatis-Plus驼峰式命名映射的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • SpringCloud项目集成Feign、Hystrix过程解析

    SpringCloud项目集成Feign、Hystrix过程解析

    这篇文章主要介绍了SpringCloud项目集成Feign、Hystrix过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Java基于logback MessageConverter实现日志脱敏方案分析

    Java基于logback MessageConverter实现日志脱敏方案分析

    本文介绍了一种日志脱敏方案,即基于logbackMessageConverter和正则匹配的方法,该方法的优点是侵入性低,工作量少,只需修改xml配置文件,适用于老项目,感兴趣的朋友跟随小编一起看看吧
    2024-10-10

最新评论