java-Linkedlist源码分析

深入分析 Java 中的 `LinkedList` 源码

`LinkedList` 是 Java 集合框架中的一个重要类,它基于双向链表实现,提供了高效的插入和删除操作。与 `ArrayList` 不同,`LinkedList` 的结构使其在特定操作上有更优的性能表现。本文将详细分析 `LinkedList` 的源码,包括其数据结构、构造方法、核心操作等。

1. `LinkedList` 的基本数据结构

`LinkedList` 是基于双向链表实现的,这意味着每个节点都包含对前一个节点和后一个节点的引用。`LinkedList` 主要由以下几个关键字段组成:

```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`:链表节点的内部类,每个节点包含元素数据和前后节点的引用。

2. 构造方法

`LinkedList` 提供了多个构造方法:

2.1 默认构造方法

```java

public LinkedList() {

}

```

默认构造方法初始化一个空的链表。

2.2 从另一个集合创建 `LinkedList`

```java

public LinkedList(Collection<? extends E> c) {

this();

addAll(c);

}

```

此构造方法从另一个集合创建 `LinkedList`,并将集合中的所有元素添加到链表中。

3. 核心操作方法

3.1 添加元素

`LinkedList` 提供了多种添加元素的方法:

3.1.1 在链表末尾添加元素

```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;

else

l.next = newNode;

size++;

modCount++;

}

```

  • `add(E e)`:在链表末尾添加元素。

  • `linkLast(E e)`:将新节点链接到链表的末尾。如果链表为空,则新节点既是 `first` 也是 `last`。

3.1.2 在指定位置插入元素

```java

public void add(int index, E element) {

checkPositionIndex(index);

if (index == size)

linkLast(element);

else

linkBefore(element, node(index));

}

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;

if (pred == null)

first = newNode;

else

pred.next = newNode;

size++;

modCount++;

}

```

  • `add(int index, E element)`:在指定位置插入元素。

  • `linkBefore(E e, Node<E> succ)`:在指定节点之前插入新节点。

  • `node(int index)`:返回指定位置的节点。

3.1.3 添加元素到链表的头部

```java

public void addFirst(E e) {

linkFirst(e);

}

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;

else

f.prev = newNode;

size++;

modCount++;

}

```

  • `addFirst(E e)`:在链表头部添加元素。

  • `linkFirst(E e)`:将新节点链接到链表的头部。如果链表为空,则新节点既是 `first` 也是 `last`。

3.2 删除元素

`LinkedList` 提供了多种删除元素的方法:

3.2.1 删除指定位置的元素

```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;

x.prev = null;

}

if (next == null) {

last = prev;

} else {

next.prev = prev;

x.next = null;

}

x.item = null;

size--;

modCount++;

return element;

}

```

  • `remove(int index)`:删除指定位置的元素。

  • `unlink(Node<E> x)`:断开指定节点的链接,并返回节点中的元素。

3.2.2 删除链表的头部元素

```java

public E removeFirst() {

final Node<E> f = first;

if (f == null)

throw new NoSuchElementException();

return unlinkFirst(f);

}

private E unlinkFirst(Node<E> f) {

final E element = f.item;

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;

}

```

  • `removeFirst()`:删除链表的头部元素。

  • `unlinkFirst(Node<E> f)`:断开头部节点的链接,并返回节点中的元素。

3.2.3 删除链表的尾部元素

```java

public E removeLast() {

final Node<E> l = last;

if (l == null)

throw new NoSuchElementException();

return unlinkLast(l);

}

private E unlinkLast(Node<E> l) {

final E element = l.item;

final Node<E> prev = l.prev;

l.item = null;

l.prev = null; // help GC

last = prev;

if (prev == null)

first = null;

else

prev.next = null;

size--;

modCount++;

return element;

}

```

  • `removeLast()`:删除链表的尾部元素。

  • `unlinkLast(Node<E> l)`:断开尾部节点的链接,并返回节点中的元素。

3.3 获取元素和修改元素

`LinkedList` 提供了获取和修改元素的方法:

3.3.1 获取元素

```java

public E get(int index) {

checkElementIndex(index);

return node(index).item;

}

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)`:返回指定位置的节点,通过判断索引位置决定从前往后还是从后往前遍历,提高效率。

3.3.2 修改元素

```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)`:根据索引修改元素,并返回旧元素。

4. 双向链表的结构特点

4.1 链表节点的定义

在 `LinkedList` 中,每个节点包含一个元素和对前后节点的引用:

```java

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`:存储节点的元素。

  • `next`:指向下一个节点。

  • `prev`:指向前一个节点。

4.2 链表的首尾节点

`LinkedList` 通过 `first` 和 `last` 字段分别指向链表的首节点和尾节点,这样可以高效地进行头部和尾部的插入和删除操作。

相关推荐
海螺姑娘的小魏3 分钟前
Effective C++ 条款 16:成对使用 `new` 和 `delete` 时要采取相同形式
开发语言·c++
neter.asia21 分钟前
C# 窗体应用程序嵌套web网页,基于谷歌浏览器内核(含源码)
开发语言·c#
Stara051121 分钟前
基于YOLOV5+Flask安全帽RTSP视频流实时目标检测
python·yolo·目标检测·flask
重整旗鼓~25 分钟前
2.flask中使用装饰器统一验证用户登录
后端·python·flask
苹果醋329 分钟前
Vue3响应式数据: 深入分析Ref与Reactive
java·运维·spring boot·mysql·nginx
杜小白也想的美32 分钟前
FlaskAPI-路径参数、查询参数
python·fastapi
EterNity_TiMe_34 分钟前
【论文复现】农作物病害分类(Web端实现)
前端·人工智能·python·机器学习·分类·数据挖掘
2301_8091774738 分钟前
sqoop,flume草稿
开发语言
缘友一世1 小时前
JAVA代理模式和适配器模式
java·代理模式·适配器模式
轻浮j1 小时前
Sentinel底层原理以及使用算法
java·算法·sentinel