java-LinkedList源码详解

devtools/2025/2/13 4:08:11/

前言:

LinkedList 是 Java 中另一个常用的集合类,它基于双向链表实现,支持高效的插入和删除操作,但随机访问性能较差

类定义和成员变量:

java">public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable {transient int size = 0; // 链表中的元素数量// 链表的头节点transient Node<E> first;// 链表的尾节点transient Node<E> last;// 内部静态类,表示链表的节点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;}}
}
  • size:链表中元素的数量。
  • first:链表的头节点。
  • last:链表的尾节点。
  • Node:内部静态类,表示链表的节点,包含数据 (item)、前驱节点 (prev) 和后继节点 (next)。

构造方法:

LinkedList 提供了两个构造方法:

java">// 构造一个空链表
public LinkedList() {
}// 构造一个包含指定集合元素的链表
public LinkedList(Collection<? extends E> c) {this();addAll(c);
}
  • 无参构造方法:创建一个空链表。
  • 使用集合构造方法:创建一个包含指定集合元素的链表。

核心方法:

添加元素

java">// 在链表末尾添加元素
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); // 创建新节点last = newNode; // 更新尾节点为新节点if (l == null) // 如果链表为空first = newNode; // 新节点也是头节点elsel.next = newNode; // 否则,将新节点链接到原尾节点的后面size++; // 链表大小增加modCount++; // 修改次数增加
}
  • add(E e):在链表末尾添加元素。
  • linkLast(E e):在链表末尾链接一个新节点。

获取元素

java">// 获取指定索引位置的元素
public E get(int index) {checkElementIndex(index); // 检查索引是否越界return node(index).item;  // 返回节点的数据
}// 检查索引是否越界
private void checkElementIndex(int index) {if (index < 0 || index >= size)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}// 返回指定索引位置的节点
Node<E> node(int 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;}
}
  • get(int index):获取指定索引位置的元素。
  • node(int index):根据索引返回节点,优化了查找性能(从头部或尾部开始遍历)。

删除元素

java">// 删除指定索引位置的元素
public E remove(int index) {checkElementIndex(index); // 检查索引是否越界return unlink(node(index)); // 删除节点并返回其数据
}// 删除指定节点
E unlink(Node<E> x) {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;    // 清除当前节点的 prev 引用}if (next == null) { // 如果删除的是尾节点last = prev;} else {next.prev = prev; // 将后继节点的 prev 指向前驱节点x.next = null;    // 清除当前节点的 next 引用}x.item = null; // 清除当前节点的数据引用,帮助 GCsize--;        // 链表大小减少modCount++;    // 修改次数增加return element;
}
  • remove(int index):删除指定索引位置的元素。
  • unlink(Node x):删除指定节点,并调整链表结构。

修改元素

java">// 修改指定索引位置的元素
public E set(int index, E element) {checkElementIndex(index); // 检查索引是否越界Node<E> x = node(index);  // 获取节点E oldVal = x.item;        // 获取旧值x.item = element;         // 设置新值return oldVal;            // 返回旧值
}
  • set(int index, E element):修改指定索引位置的元素。

其他方法

队列操作

LinkedList 实现了 Deque 接口,支持队列和双端队列操作:

java">// 在链表头部添加元素
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; // 新节点也是尾节点elsef.prev = newNode; // 否则,将新节点链接到原头节点的前面size++; // 链表大小增加modCount++; // 修改次数增加
}// 在链表尾部添加元素
public void addLast(E e) {linkLast(e);
}// 获取链表头部元素
public E getFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return f.item;
}// 获取链表尾部元素
public E getLast() {final Node<E> l = last;if (l == null)throw new NoSuchElementException();return l.item;
}

工具方法

java">// 返回链表大小
public int size() {return size;
}// 判断链表是否为空
public boolean isEmpty() {return size == 0;
}// 清空链表
public void clear() {for (Node<E> x = first; x != null; ) {Node<E> next = x.next;x.item = null;x.next = null;x.prev = null;x = next;}first = last = null;size = 0;modCount++;
}

序列化

LinkedList 实现了 Serializable 接口,支持序列化。由于 first 和 last 是 transient 的,LinkedList 自定义了序列化和反序列化的逻辑:

java">private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException {s.defaultWriteObject();s.writeInt(size); // 写入链表大小// 遍历链表,写入每个元素for (Node<E> x = first; x != null; x = x.next)s.writeObject(x.item);
}private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {s.defaultReadObject();int size = s.readInt(); // 读取链表大小// 遍历链表,读取每个元素并添加到链表中for (int i = 0; i < size; i++)linkLast((E) s.readObject());
}

总结

LinkedList 是一个基于双向链表实现的列表,支持高效的插入和删除操作,但随机访问性能较差。它的核心操作(如添加、删除、获取、修改)都是通过操作链表节点来实现的。


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

相关文章

zsh: command not found: conda

场景描述 在 Linux 服务器上使用 zsh 时&#xff0c;如果出现 zsh: command not found: conda 错误&#xff0c;说明你的系统未正确配置 conda 命令&#xff0c;或者你尚未安装 Anaconda/Miniconda。 解决方案 确保已安装 Anaconda 或 Miniconda conda 是 Anaconda 或 Minico…

java后端开发day14--之前练习的总结和思考

1.感受 这两天学点儿新的就直接上手打代码&#xff0c;真的是累死个人。我唯一的感受就是&#xff0c;课听完了&#xff0c;代码也跟着打完了&#xff08;是的&#xff0c;跟着打的&#xff0c;没自己打&#xff09;&#xff0c;感觉自己脑袋里乱乱的&#xff0c;对代码的分区…

【05】RUST常用的集合函数宏类型

文章目录 常用集合VecStringHashMap 宏打印 类型Option<T> 常用集合 Vec 堆上连续内存vector可能出现扩容&#xff0c;把老元素copy到内存新位置 因此不允许let first &v[0];作用域内调用v.push(4); // 定义 let v: Vec<i32> Vec::new(); let v vec![1,…

2025 年 2 月 TIOBE 指数

2025 年 2 月 TIOBE 指数 二月头条:快,更快,最快! 现在,世界需要每秒处理越来越多的数字,而硬件的发展速度却不够快,程序的速度变得越来越重要。话虽如此,快速编程语言在 TIOBE 指数中取得进展也就不足为奇了。编程语言 C++ 最近攀升至第 2 位,Go 已稳居前 10 名,Ru…

HALCON 数据结构

目录 1. HALCON基本数据分类 1.1 图像相关数据 1.1.1 Image(图片) 1.1.2 Region(区域) 1.1.3 XLD(轮廓) 1.2 控制类数据 1.2.1 基本控制数据类型 1.2.2 handle(句柄) 2. 数组与字典 2.1 数组类型及特点 2.1.1 Iconic数组(Objects) 2.1.2 Control数组(Tu…

智能同义词处理与命中优化:提升知识库查询精度

效果展示(环境依赖请参看上一篇文章): qa.json(示例知识): 测试结果: 引言 在构建智能问答系统时,常常遇到用户提问方式多样化的问题。即使问题本质相同,表达方式可能千差万别。为了提高搜索和匹配的准确性,我们需要对原始问题进行扩展,即生成多个同义表达。这…

Rust 测试指南:从入门到进阶

1. 测试基础&#xff1a;#[test] 属性 Rust 测试的基本单位是函数。只要在一个函数前面标注 #[test] 属性&#xff0c;那么在运行 cargo test 时&#xff0c;Rust 会自动识别并执行它。例如&#xff0c;新建一个库工程 adder&#xff0c;cargo new adder --lib&#xff0c;在 …

使用 Python-pptx 库提取 PPTX 文件中的结构与文字

是的&#xff0c;使用 python-pptx 库是提取 PPTX 文件中结构和文字的理想选择&#xff0c;原因如下&#xff1a; 专门处理 PPTX 格式 python-pptx 是一个专门为处理 PPTX 文件&#xff08;.pptx 格式&#xff09;而设计的 Python 库。 它可以读取和操作 PPTX 文件的内部结构…