您的位置:首页 > 汽车 > 时评 > 软件开发项目管理操作_优设网址导航属于网络导航吗_今日新闻最新消息_河南seo网站多少钱

软件开发项目管理操作_优设网址导航属于网络导航吗_今日新闻最新消息_河南seo网站多少钱

2025/3/11 15:38:06 来源:https://blog.csdn.net/Gaomengsuanjia_/article/details/144378671  浏览:    关键词:软件开发项目管理操作_优设网址导航属于网络导航吗_今日新闻最新消息_河南seo网站多少钱
软件开发项目管理操作_优设网址导航属于网络导航吗_今日新闻最新消息_河南seo网站多少钱

图解LinkedList底层原理


本篇将讲解Java中的一个集合LinkedList的底层实现原理,会查看并分析底层源码,结合图解的方式,理解其添加数据的过程

数据结构

LinkedList 是基于双向链表实现的,节点结构如下:

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;}
}
  • 每个节点存储当前元素的值(item)及指向前后节点的引用(prevnext
  • LinkedList 是一个双向链表,支持从头部或尾部高效地插入和删除
First
Node 1
prev: null
item
next: Node2
Node 2
prev: Node1
item
next: Node3
Node 3
prev: Node2
item
next: Last
Last

成员变量

LinkedList 的核心成员变量如下:

transient int size = 0;      // 链表中元素的数量
transient Node<E> first;     // 链表的头节点
transient Node<E> last;      // 链表的尾节点
  • size:记录链表中元素的数量
  • first:指向链表的头节点
  • last:指向链表的尾节点

构造方法

LinkedList 提供了默认的无参构造方法:

public LinkedList() {}
  • LinkedList 初始化时,firstlast 都为 null,表示链表为空。

add 方法源码分析

当我们调用 add(E e) 方法时,例如:

LinkedList<String> list = new LinkedList<>();
list.add("Hello");

以下是 add 方法的源码:

public boolean add(E e) {linkLast(e);return true;
}
  • add 方法通过调用 linkLast(E e) 方法,将新元素添加到链表尾部

linkLast 方法解析

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;     // 新节点即为头节点elsel.next = newNode;    // 更新旧尾节点的 next 引用size++;                  // 链表长度加 1modCount++;              // 修改计数器
}

当我add第一个元素e时,他的插入过程如下:

  1. 新节点创建

    final Node<E> l = last;  // 获取当前尾节点
    final Node<E> newNode = new Node<>(l, e, null)
    last = newNode;          // 更新尾节点
    

    通过 Node 构造方法,将新节点的 prev 指向当前尾节点,当前尾节点为null,所以prev指向null,next 指向 null,再将尾节点last指向新节点

    First
    Node 1
    prev: null
    item:e
    next:null
    Last
  2. 更新链表结构

    if (l == null)           // 如果链表为空first = newNode;     // 新节点即为头节点elsel.next = newNode;
    
    • 如果链表为空(l == null),更新头节点 first
    • 如果链表非空,将当前尾节点的 next 指向新节点

    此时的l是未更新之前的last,为null,所以更新头节点也指向Node 1

    First
    Node 1
    prev: null
    item:e
    next:null
    Last
  3. 更新尾节点和链表长度:新节点成为尾节点,size 自增


接着我们再add第二个元素e2,同样的步骤再次执行:

  1. 新节点创建

    final Node<E> l = last;  // 获取当前尾节点
    final Node<E> newNode = new Node<>(l, e, null)
    last = newNode;          // 更新尾节点
    

    在添加第一个元素时,尾节点更新为了Node 1,此时的把尾节点赋值给ll的值为Node 1

    创建一个新节点传入了l因此新节点的prev指向Node 1,next为null,并且更新尾节点,把尾节点指向新节点,此时last的值就为Node 2了

    First
    Node 1
    prev: null
    item: e
    next: null
    Node 2
    prev: Node 1
    item: e2
    next: null
    Last
  2. 更新链表结构:

    if (l == null)           // 如果链表为空first = newNode;     // 新节点即为头节点elsel.next = newNode;
    

    此时的l早已不是null了,而是Node1,因此走else的逻辑,将l, 也就是Node 1的next指向新节点,形成一个双向指针

    First
    Node 1
    prev: null
    item: e
    next: Node 2
    Node 2
    prev: Node 1
    item: e2
    next: null
    Last
  3. 更新尾节点和链表长度:新节点成为尾节点,size 自增

此时双向链表的雏形已经形成


接着我们再次add一个新元素e3,依旧是同样的操作:

  1. 新节点创建

    final Node<E> l = last;  // 获取当前尾节点
    final Node<E> newNode = new Node<>(l, e, null)
    last = newNode;          // 更新尾节点
    

    经过e2的插入过程,last此时为Node2,创建新节点时,其prev就为Node2,last 也更新为了Node3

    First
    Node 1
    prev: null
    item: e
    next: Node 2
    Node 2
    prev: Node 1
    item: e2
    next: null
    Node 3
    prev: Node 2
    item: e3
    next: null
    Last
  2. 更新链表结构:

    if (l == null)           // 如果链表为空first = newNode;     // 新节点即为头节点elsel.next = newNode;
    

    依旧执行else,将Node 2 的next指向Node 3,形成双向链表:

    First
    Node 1
    prev: null
    item: e
    next: Node 2
    Node 2
    prev: Node 1
    item: e2
    next: Node 3
    Node 3
    prev: Node 2
    item: e3
    next: null
    Last

linkBefore 方法

void linkBefore(E e, Node<E> succ) {final Node<E> pred = succ.prev; // 获取前驱节点final Node<E> newNode = new Node<>(pred, e, succ); // 创建新节点succ.prev = newNode; // 更新后继节点的 previf (pred == null)    // 如果插入位置为头部first = newNode;elsepred.next = newNode; // 更新前驱节点的 nextsize++;modCount++;
}

该方法与尾插法类似,节点的插入位置变成了从头节点位置插入

具体流程:

  1. 确定插入位置的前驱和后继节点
  2. 更新新节点的 prevnext 引用,同时修改前驱和后继节点的指针
  3. 如果插入位置为链表头部或尾部,更新 firstlast 节点

插入到指定位置

add(int index, E element)

add 方法支持在链表的任意位置插入元素:

public void add(int index, E element) {checkPositionIndex(index); // 检查索引范围if (index == size) // 如果插入到链表尾部linkLast(element);elselinkBefore(element, node(index));
}

关键逻辑

  • 边界判断:通过 checkPositionIndex() 检查索引是否越界
  • 插入方式:
    • 如果插入位置为链表尾部,调用 linkLast 方法
    • 如果插入位置在中间,调用 linkBefore 方法

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com