Java LinkedList解密

news2024/11/27 6:16:37

一、LinkedList最底层的原理

        LinkedList其实底层是链表:

        当初始化的时候,会将链表这个节点的值、prev指针和next指针初始化。

二、LinkedList初始化

 

        无参构造并没有做什么。有参构造会先调用无参构造,然后调用addAll方法将链表的节点都初始化:

二、增加元素

2.1 add(object)

        调用了linkLast方法。就是在尾部添加元素

2.1.1 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;
    else
        l.next = newNode; // 否则将新节点链接到链表的尾部
    size++; // 增加链表的元素个数
}

         常见的双向链表插入元素的逻辑。不得不说,jdk的代码还是很简洁的。这里画个图示:

        当插入空链表时:

        当链表中有一个元素时:

 

二、删除元素 

2.1 remove() 

 

        无参的remove调用的是removeFirst(),可以看出是从头开始删的。这个函数放在后面讲。

2.2 remove(object)

 

        删除指定的元素,这个删除逻辑和ArrayList一样,有兴趣的可以看看我讲解的ArrayList源码:Java ArrayList解密-CSDN博客

public boolean remove(Object o) {
    if (o == null) { // 如果要删除的元素为 null
        for (Node<E> x = first; x != null; x = x.next) { // 遍历链表
            if (x.item == null) { // 如果节点的元素为 null
                unlink(x); // 删除节点
                return true; // 返回 true 表示删除成功
            }
        }
    } else { // 如果要删除的元素不为 null
        for (Node<E> x = first; x != null; x = x.next) { // 遍历链表
            if (o.equals(x.item)) { // 如果节点的元素等于要删除的元素
                unlink(x); // 删除节点
                return true; // 返回 true 表示删除成功
            }
        }
    }
    return false; // 如果链表中不包含要删除的元素,则返回 false 表示删除失败
}

 2.2.1 unlink()

        顾名思义,其实就是取消这个节点和链表的连接关系。他更新要删除的这个节点的prev和next指针,并将当前节点置为null便于GC

 

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--; // 减少链表的元素个数
    return element; // 返回被删除节点的元素
}

2.3 removeFirst() 

 

        先判断链表内有没有元素,然后调用unlinkFist()方法删除

2.3.1 unlinkFist()

 

private E unlinkFirst(Node<E> f) {
    final E element = f.item; // 获取要删除的节点的元素
    final Node<E> next = f.next; // 获取要删除的节点的下一个节点
    f.item = null; // 将要删除的节点的元素设置为 null
    f.next = null; // 将要删除的节点的下一个节点设置为 null
    first = next; // 将链表的头节点设置为要删除的节点的下一个节点
    if (next == null) // 如果链表只有一个节点
        last = null; // 将链表的尾节点设置为 null
    else
        next.prev = null; // 将要删除节点的下一个节点的前驱设置为 null
    size--; // 减少链表的大小
    return element; // 返回被删除节点的元素
}

        说白了就是把first指针指向的节点去掉,然后将first指针指向下一个节点,再将当前first的prev置为null

2.4 removeLast() 

        逻辑上和removeFirst()差不多,就不多赘述了。

 

三、修改

3.1 set(index, object)

public E set(int index, E element) {
    checkElementIndex(index); // 检查索引是否超出范围
    Node<E> x = node(index); // 获取要替换的节点
    E oldVal = x.item; // 获取要替换节点的元素
    x.item = element; // 将要替换的节点的元素设置为指定元素
    return oldVal; // 返回替换前的元素
}

3.1.1 node方法

        找到索引位置的元素。

        比较有意思的点是,他会判断索引位置在链表前半段还是后半段。如果在前半段,就从前面遍历链表;如果在后半段,就从后面遍历链表 

 

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; // 返回指定位置的节点
    }
}

四、查找元素 

4.1 get(index) 

        查找索引处元素 

 

        检查索引后,调用node方法找到元素,node方法在前面讲过了,这里略去。

4.2 indexOf(object) 

        查找指定元素

 

         逻辑和ArrayList的indexOf一致,都是直接遍历

五、和ArrayList的比较 

        敬请期待下一章 

 

 

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

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

相关文章

GaussDB数据库使用COPY命令导数

目录 一、前言 二、GaussDB数据库使用COPY命令导数语法 1、语法COPY FROM 2、语法COPY TO 3、特别说明及参数示意 三、GaussDB数据库使用COPY命令导数示例 1、操作步骤 2、准备工作&#xff08;示例&#xff09; 3、把一个表的数据拷贝到一个文件&#xff08;示例&…

Web应用开发:介绍

Web应用开发&#xff0c;介绍一下 文心一言&#xff08;文心大模型3.5&#xff09; Web应用开发是一种使用Web技术创建和部署应用程序的过程。Web应用通常是指通过网络浏览器访问的应用程序&#xff0c;它们可以提供各种功能&#xff0c;如在线银行、在线购物、社交媒体平台等…

2020年认证杯SPSSPRO杯数学建模D题(第一阶段)让电脑桌面飞起来全过程文档及程序

2020年认证杯SPSSPRO杯数学建模 D题 让电脑桌面飞起来 原题再现&#xff1a; 对于一些必须每天使用电脑工作的白领来说&#xff0c;电脑桌面有着非常特殊的意义&#xff0c;通常一些频繁使用或者比较重要的图标会一直保留在桌面上&#xff0c;但是随着时间的推移&#xff0c;…

优雅地展示20w单细胞热图|非Doheatmap 超大数据集 细胞数太多

单细胞超大数据集的热图怎么画&#xff1f;昨天刚做完展示20万单细胞的热图要这么画吗&#xff1f; 今天就有人发消息问我为啥他画出来的热图有问题。 问题起源 昨天分享完 20万单细胞的热图要这么画吗&#xff1f;&#xff0c;就有人问为啥他的数据会出错。我们先来看下他的…

【Vue2+3入门到实战】(21)认识Vue3、使用create-vue搭建Vue3项目、熟悉项目和关键文件

目录 一、认识Vue31. Vue2 选项式 API vs Vue3 组合式API2. Vue3的优势 二、 使用create-vue搭建Vue3项目1. 认识create-vue2. 使用create-vue创建项目 三、 熟悉项目和关键文件四、总结 一、认识Vue3 1. Vue2 选项式 API vs Vue3 组合式API <script> export default {…

Django Web 开发实战-实现用户管理系统(部门管理、用户管理、注册登录、文件上传)

简介 基于Django Python Web框架 MySQL Bootstrap 开发的用户管理系统。支持增删改查、模糊搜索、分页。 功能介绍 部门管理---》已完成 用户管理---》已完成 认证&#xff08;注册/登录&#xff09;---》开发中 数据统计---》待开发 文件上传---》待开发 效果图 部门…

《绝地求生》改名卡快速获得方法 绝地求生改名卡怎么获得

《绝地求生》改名卡是很多小伙伴所在意的物品&#xff0c;购买通行证后需要提升一定的等级才能入手&#xff0c;而怎么升级最快最划算呢&#xff1f;今天闲游盒带来“米奇”分享的《绝地求生》改名卡快速获得方法&#xff0c;赶紧来试试吧。 吃鸡刚刚迎来了更新&#xff0c;通行…

CSDN规则详解(三)

文章目录 每日一句正能量前言企业博客如何开通企业博客分类专栏付费专栏开通规则博客搬家后记 每日一句正能量 只有经历过风雨的人生&#xff0c;才能看到彩虹的美丽&#xff1b;只有付出努力的人&#xff0c;才能品味到成功的滋味&#xff1b;只有懂得感恩的人&#xff0c;才能…

QProgressDialog用法及结合QThread用法,四种线程使用

1 QProgressDialog概述 QProgressDialog类提供耗时操作的进度条。 进度对话框用于向用户指示操作将花费多长时间&#xff0c;并演示应用程序没有冻结。此外&#xff0c;QPorgressDialog还可以给用户一个中止操作的机会。 进度对话框的一个常见问题是很难知道何时使用它们;操作…

HTTP 错误 401.3 - Unauthorized 由于Web服务器上此资源的访问控制列表(ACL)配置或加密设置。

用IIS 发布网站&#xff0c;不能访问且出现错误&#xff1a; HTTP 错误 401.3 - Unauthorized 由于Web服务器上此资源的访问控制列表(ACL)配置或加密设置。您无权查看此目录或页面 解决办法&#xff1a; 1.打开IIS界面&#xff0c;选中发布的网站&#xff0c;右键—>编辑…

【C语言】Linux socket 编程

一、Socket 通信过程 在 Linux 系统中&#xff0c;socket 是一种特殊的文件描述符&#xff0c;用于在网络中的不同主机间或者同一台主机中的不同进程间进行双向通信。它是通信链路的端点&#xff0c;可以看作是网络通信的接口。Socket 通信过程主要分为以下几个步骤&#xff1a…

canvas绘制直角梯形(向右)

查看专栏目录 canvas示例教程100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

PTA QQ帐户的申请与登陆

QQ帐户的申请与登陆 分数 25 全屏浏览题目 作者 DS课程组 单位 浙江大学 实现QQ新帐户申请和老帐户登陆的简化版功能。最大挑战是&#xff1a;据说现在的QQ号码已经有10位数了。 输入格式: 输入首先给出一个正整数N&#xff08;≤105&#xff09;&#xff0c;随后给出N行…

微服务-Gateway

案例搭建 官网地址 父Pom <com.alibaba.cloud.version>2.2.8.RELEASE</com.alibaba.cloud.version> <com.cloud.version>Hoxton.SR12</com.cloud.version> <com.dubbo.version>2.2.7.RELEASE</com.dubbo.version> <dependencyManagem…

Python基础-05(输出输入、if、if else和elif)

文章目录 前言一、输出&#xff08;print()&#xff09;和输入&#xff08;input()&#xff09;二、if、if else、elif1.if2.if else3.关于输入input的默认值4.elif 前言 今天复习一些非常基础的内容&#xff0c;以及if、if else和elif语句 一、输出&#xff08;print()&…

【vue/uniapp】pdf.js 在一些型号的手机上不显示

引入&#xff1a; uniapp 项目通过 pdf.js 来在线浏览 pdf 链接&#xff0c;在微信小程序中都显示正常&#xff0c;但是通过 app 跳转小程序&#xff0c;在苹果、小米显示正常&#xff0c;但是华为和 oppo 就不显示&#xff0c;可以通过降 pdf.js 的版本来解决这个问题。 解决&…

1.3 力扣二叉树中等题

题目一&#xff1a; 669. 修剪二叉搜索树 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果没有被移除&…

python flask图书管理系统带文档

python flask图书管理系统带文档。功能&#xff1a;登录&#xff0c;图书的增删改查&#xff0c;读者管理&#xff0c;借阅记录&#xff0c;有文档。 技术&#xff1a;python3,flask,mysql,html。 包含源码数据库文件文档。 源码下载地址&#xff1a; https://download.csd…

Calibre PEX Hspice Netlist提取步骤(数模芯片提取spice netlist流程)

在数模混合芯片中&#xff0c;通常模拟需要数字模块通过calibre工具来提取Hspice netlist用于功耗仿真。注意这里的spice netlist和做Calibre的spice netlist是不太一样的。 另外在做calibre pex时需要确保当前的design LVS已经pass。否则功耗仿真可能会不准。 Calibre LVS常…

Z-score 因子的深入思考

最新&#xff08;2024 年 1 月&#xff09;出版的 SC 技术分析&#xff08;Techical Analysis of Stock & Commodities&#xff09;的第 4 条文章给到了 Z-score&#xff0c;原文标题为《Z-score: How to use it in Trading》。今天的笔记&#xff0c;就借此机会&#xff0…