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` 字段分别指向链表的首节点和尾节点,这样可以高效地进行头部和尾部的插入和删除操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/41279.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android 进程,线程调度的区别

一 分析&#xff1a; 进程和线程在调度上有什么不同呢&#xff1f;当有一个task去占用指定的资源时候叫进程&#xff0c;当有多个task去共享使用这些资源时候&#xff0c;这个task和之后的task都叫线程&#xff08;最初这个task叫主线程&#xff09;而linux调度主要调的就是cp…

【Portswigger 学院】文件上传

教程和靶场来源于 Burpsuite 的官网 Portswigger&#xff1a;File upload vulnerabilities - PortSwigger 原理与危害 很多网站都有文件上传的功能&#xff0c;比如在个人信息页面允许用户上传图片作为头像。如果网站应用程序对用户上传的文件没有针对文件名、文件类型、文件内…

前端基础:JavaScript(篇一)

目录 JavaScript概述 JavaScript历史&#xff1a; 须知&#xff1a; 基本语法 变量 代码 运行 数据类型 1、数值型(number)&#xff1a; 代码 运行 2、布尔型(boolean)&#xff1a; 代码 运行 3、字符串型&#xff1a; 代码 运行 4、 undefined类型 代码…

TCP的pop网络模式

TCP的pop网络模式 1、tcp连接的状态有以下11种 CLOSED&#xff1a;关闭状态LISTEN&#xff1a;服务端状态&#xff0c;等待客户端发起连接请求SYN_SENT&#xff1a;客户端已发送同步连接请求&#xff0c;等待服务端相应SYN_RECEIVED&#xff1a;服务器收到客户端的SYN请请求&…

MySQL 基本语法讲解及示例(下)

第六节&#xff1a;如何检索资料 在本节中&#xff0c;我们将介绍如何使用SQL语句检索数据库中的资料&#xff0c;具体包括选择特定列、排序、条件过滤以及组合排序等操作。我们以一个名为student的表格为例&#xff0c;演示不同的检索方法。 初始表格 student student_idname…

修复harbor的/account/sign-in\?globalSearch=b不登录可以查询镜像的问题

Nginx的location指令不能直接匹配查询参数&#xff0c;所以需要通过其他方式来处理。这里是一个使用if指令结合查询参数来实现的方法。该方法会在请求路径中带有特定查询参数时返回404。 使用if指令匹配查询参数 打开Nginx配置文件&#xff1a; sudo vim /etc/nginx/sites-ava…

Python中frozenset,秒变不可变集合,再也不用担心多线程了!

目录 1、Frozenset基础介绍 🌐 1.1 Frozenset定义与创建 1.2 不可变集合特性 1.3 与Set的区别对比 2、Frozenset操作实践 🧩 2.1 初始化与添加元素尝试 2.2 成员测试: in & not in 2.3 集合运算: 并集、交集、差集 2.4 使用场景示例: 字典键、函数参数默认值 …

登录设计(实战项目)-1个手机号多用户身份登录

一. 背景&#xff1a; 该需求是一个互联网医院的预约单场景&#xff0c;护士在小程序上申请患者查房预约单&#xff0c;医生在小程序上对预约单进行接单&#xff0c;护士开始查房后填写查房小结&#xff0c;客户需要对用户信息进行授权&#xff0c;医生查房后进行签字&#xff…

劲爆!华为享界两款新车曝光,等等党有福了

文 | AUTO芯球 作者 | 雷慢 劲爆啊&#xff0c;北汽的一份环境影响分析报告&#xff0c; 不仅曝光了享界S9的生产进展&#xff0c; 还泄露了自家的另两款产品&#xff0c; 第一款是和享界S9同尺寸的旅行车&#xff0c; 我一看&#xff0c;这不是我最喜欢的“瓦罐”吗&…

v-html 空格/换行不生效

接口返回的内容如下&#xff1a;有空格有换行&#xff0c;但 使用v-html无效 需加css样式 white-space: pre-wrap; <div class"pretty-html" v-html"Value"></div>.pretty-html {white-space: pre-wrap; /* 保留空格和换行&#xff0c;并允许…

掌握麦肯锡精英的6个技巧,你也能成为1%的精英!

不知道大家有没有想过&#xff0c;我们和那些全球顶尖精英的差距可能只有1%&#xff0c;只是99%的人还不知道这件事。 今天给大家推荐一本好书&#xff0c;《你和麦肯锡精英的差别只有1%》。优思学院发现&#xff0c;在我们的六西格玛、精益管理的学生中很多人对自己没有自信。…

软通动力子公司鸿湖万联最新成果SwanLink AI亮相世界人工智能大会

7月4日&#xff0c;2024世界人工智能大会暨人工智能全球治理高级别会议&#xff08;WAIC 2024&#xff09;在上海拉开帷幕&#xff0c;软通动力董事长兼首席执行官刘天文受邀出席开幕式。其间&#xff0c;软通动力携子公司鸿湖万联深度参与到大会各项活动中&#xff0c;并全面展…

C语言_结构体初阶(还未写完)

结构体的声明 1. 什么是结构&#xff1f;结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量 数组&#xff1a;一组相同类型元素的集合 结构体&#xff1a;一组不一定相同类型元素的集 2. 结构的声明 struct tag //tag根据实际情况给名字…

Spring注解@Qualifier

Autowired 注解是 Spring 依赖注入。但是有些场景下仅仅靠这个注解不足以让Spring知道到底要注入哪个 bean。 默认情况下&#xff0c;Autowired 按类型装配 Spring Bean。 如果容器中有多个相同类型的 bean&#xff0c;则框架将抛出 NoUniqueBeanDefinitionException&#xff0…

数字化产科管理平台全套源码,java产科电子病历系统源码

数字化产科管理平台全套成品源码&#xff0c;产科电子病历系统源码&#xff0c;多家大型妇幼专科医院应用案例。源码完全授权交付。 数字化产科管理平台&#xff08;智慧产科系统&#xff09;是为医院产科量身定制的信息管理系统。它管理了孕妇从怀孕开始到生产结束42天以内的一…

数据库MySQL学习笔记

数据库MySQL学习笔记 主要记录常见的MySQL语句学习过程&#xff0c;增删改查。 -- 显示所有数据库 SHOW DATABASES;-- 创建新数据库 CREATE DATABASE mydatabase;-- 使用数据库 USE mydatabase;-- 显示当前数据库中的所有表 SHOW TABLES;-- 创建新表 CREATE TABLE users (id …

BERT--学习

一、Transformer Transformer&#xff0c;是由编码块和解码块两部分组成&#xff0c;其中编码块由多个编码器组成&#xff0c;解码块同样也是由多个解码块组成。 编码器&#xff1a;自注意力 全连接 多头自注意力&#xff1a;Q、K、V 公式&#xff1a; 解码块&#xff1…

【Hive实战】 HiveMetaStore的指标分析

HiveMetaStore的指标分析&#xff08;一&#xff09; 文章目录 HiveMetaStore的指标分析&#xff08;一&#xff09;背景目标部署架构 hive-site.xml相关配置元数据服务的指标相关配置 源码部分&#xff08;hive2.3系&#xff09;JvmPauseMonitor.javaHiveMetaStore的内部类HMS…

【anaconda】—“conda info“命令后conda配置和环境信息的理解

文章目录 conda配置和环境信息的理解 conda配置和环境信息的理解 安装anaconda成功后&#xff0c;打开cmd&#xff0c;输入"conda info"命令&#xff0c;结果显示如下&#xff1a; conda的配置和环境信息的输出。以下是对每个字段的解释&#xff1a; active environm…

H2 Database Console未授权访问漏洞封堵

背景 H2 Database Console未授权访问&#xff0c;默认情况下自动创建不存在的数据库&#xff0c;从而导致未授权访问。各种未授权访问的教程&#xff0c;但是它怎么封堵呢&#xff1f; -ifExists 很简单&#xff0c;启动参数添加 -ifExists &#xff0c;它的含义&#xff1a…