LinkedList部分底层源码分析

devtools/2024/9/24 4:22:09/

JDK版本为1.8.0_271,以插入和删除元素为例,LinkedList部分源码如下:

java">//属性,底层结构为双向链表
transient Node<E> first; //记录第一个结点的位置
transient Node<E> last; //记录最后一个结点的尾元素
transient int size = 0; //记录链表的元素个数//内部Node类定义如下
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;}
}//构造器
public LinkedList() {
}//方法:add()相关方法
public boolean add(E e) {linkLast(e); //默认把新元素链接到链表尾部return true;
}// 尾部插入一个新节点
void linkLast(E e) {final Node<E> l = last; //用 l 记录原来的最后一个结点//创建新结点final Node<E> newNode = new Node<>(l, e, null);//现在的新结点是最后一个结点了last = newNode;//如果l==null,说明原来的链表是空的if (l == null)//那么新结点同时也是第一个结点first = newNode;else//否则把新结点链接到原来的最后一个结点的next中l.next = newNode;//元素个数增加size++;//修改次数增加modCount++;
}//方法:获取get()相关方法
public E get(int index) {// 校验index是否越界,合法范围:[0,size)checkElementIndex(index);return node(index).item;
} //方法:插入add()相关方法
public void add(int index, E element) {checkPositionIndex(index); // 校验index是否越界,合法范围:[0,size)if (index == size)//如果index==size,链接到当前链表的尾部linkLast(element);elselinkBefore(element, node(index));
}// 查找index位置节点
Node<E> node(int index) {// assert isElementIndex(index);/*index < (size >> 1)采用二分思想,先将index与长度size的一半比较,如果index<size/2,就只从位置0往后遍历到位置index处;如果index>size/2,就只从位置size往前遍历到位置index处。这样可以减少一部分不必要的遍历。*///如果index<size/2,就从前往后找目标结点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;}
}//把新结点插入到[index]位置的结点succ前面,succ是[index]位置对应的结点
void linkBefore(E e, Node<E> succ) {// assert succ != null;final Node<E> pred = succ.prev; //[index]位置的前一个结点//新结点的prev是原来[index]位置的前一个结点//新结点的next是原来[index]位置的结点final Node<E> newNode = new Node<>(pred, e, succ);//[index]位置对应的结点的prev指向新结点succ.prev = newNode;//如果原来[index]位置对应的结点是第一个结点,那么现在新结点是第一个结点if (pred == null)first = newNode;elsepred.next = newNode;//原来[index]位置的前一个结点的next指向新结点size++;modCount++;
}//方法:remove()相关方法
public boolean remove(Object o) {//分o是否为空两种情况if (o == null) {//找到o对应的结点xfor (Node<E> x = first; x != null; x = x.next) {if (x.item == null) {unlink(x);//删除x结点return true;}}} else {//找到o对应的结点xfor (Node<E> x = first; x != null; x = x.next) {if (o.equals(x.item)) {unlink(x);//删除x结点return true;}}}return false;
}
// 将节点x从链表中取下
E unlink(Node<E> x) {//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 {//被删除结点不是第一个结点//被删除结点的上一个结点的next指向被删除结点的下一个结点prev.next = next;//断开被删除结点与上一个结点的链接x.prev = null;//使得GC回收}//如果被删除结点的后面没有结点,说明被删除结点是最后一个结点if (next == null) {//那么被删除结点的上一个结点变为最后一个结点last = prev;} else {//被删除结点不是最后一个结点//被删除结点的下一个结点的prev执行被删除结点的上一个结点next.prev = prev;//断开被删除结点与下一个结点的连接x.next = null;//使得GC回收}//把被删除结点的数据也置空,使得GC回收x.item = null;//元素个数减少size--;//修改次数增加modCount++;//返回被删除结点的数据return element;
}// 删除index位置的节点
public E remove(int index) { //index是要删除元素的索引位置// 校验index范围checkElementIndex(index);// 将节点x从链表中取下return unlink(node(index));
}// 插入新节点链表头结点
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;	// 将链表last指向新的头结点else	// 双端链表,将原头结点的prev指向新的头结点f.prev = newNode;size++;	// 链表节点数+1modCount++;	// 链表修改次数+1
}// 获取链表的头结点的元素
public E getFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return f.item;
}
// addLast尾插法插入节点,getLast获取链表尾结点

插入删除结点的过程如图所示:

  • 只有1个元素的LinkedList

  • 包含4个元素的LinkedList

在这里插入图片描述

  • add(E e)方法

  • add(int index,E e)方法

在这里插入图片描述

  • remove(Object obj)方法

在这里插入图片描述

  • remove(int index)方法

在这里插入图片描述


http://www.ppmy.cn/devtools/2635.html

相关文章

maven 项目示例

maven 项目 <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><properti…

Apache Storm的详细配置

Apache Storm的详细配置主要涉及以下几个方面: Zookeeper配置:Apache Storm使用Zookeeper来进行协调和配置管理。你需要配置Zookeeper集群的连接信息,包括Zookeeper服务器的主机和端口。 Storm Nimbus配置:Nimbus是Storm的主节点,负责分配任务给各个工作节点。你需要配置N…

Rust常见陷阱 | 失效的可变性

Rust 作为一门系统编程语言,最大的卖点之一在于其内存安全的保证。这种保证很大程度上得益于其变量绑定(Binding)规则中的一项核心特性:不变性(Immutability)。然而,不当的使用不变性可能会导致一些编程陷阱。在本文中,我将详细探讨 Rust 编程中的不变性陷阱,并以丰富…

K8S哲学 - 常见的资源类型

资源类型 namespace kubectl apply 和 kubectl create kubectl apply是声明式的 和 kubectl create是命令式的对吗 deployment 和 job的区别 k8s 的 lable 的意义

js如何設置滾動到元素位置

在JavaScript中&#xff0c;你可以使用window.scrollTo()方法或元素的scrollIntoView()方法来设置滚动位置。这些方法允许你将页面滚动到特定的坐标或元素。 使用 window.scrollTo() window.scrollTo() 方法接受两个参数&#xff1a;x坐标和y坐标&#xff0c;分别代表水平滚动…

「探索C语言内存:动态内存管理解析」

&#x1f320;先赞后看&#xff0c;不足指正!&#x1f320; &#x1f388;这将对我有很大的帮助&#xff01;&#x1f388; &#x1f4dd;所属专栏&#xff1a;C语言知识 &#x1f4dd;阿哇旭的主页&#xff1a;Awas-Home page 目录 引言 1. 静态内存 2. 动态内存 2.1 动态内…

大数据行业英语单词巩固20240413

Integration - 整合 Example: The integration of new software into our system will improve efficiency. 示例&#xff1a;将新软件集成到我们的系统中将提高效率。 Automation - 自动化 Example: Automation of repetitive tasks can save time and reduce errors. 示例&a…

WebApis知识总结以及案例(续3)

综合案例 小兔鲜页面注册 分析业务模块 发送验证码模块 用户点击之后&#xff0c;显示05 秒后重新获取 时间到了&#xff0c;自动改为重新获取 //1.发送短信验证码模块const codedocument.querySelector(.code)let flagtrue//通过一个变量来控制 节流阀 // 1.1 点击事件co…