集合框架----源码解读LinkedList篇

news2025/1/18 10:59:38

1.LinkedList官方介绍

双链表实现的list和Deque接口。实现所有可选的列表操作,并允许所有元素(包括null)。
所有的操作都按照双链表的预期执行。索引到列表中的操作将从列表的开始或结束遍历列表,以更接近指定索引的为准。
注意,这个实现不是同步的。如果多个线程并发访问一个链表,并且其中至少有一个线程在结构上修改了链表,那么它必须在外部同步。(结构修改是添加或删除一个或多个元素的任何操作;仅仅设置元素的值并不是结构修改。)这通常是通过在自然封装列表的某些对象上同步来实现的。如果不存在这样的对象,则应该使用集合“包装”列表。synchronizedList方法。这最好在创建时完成,以防止意外的不同步访问列表:
列表列表=集合。synchronizedList(新LinkedList(…));
这个类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在迭代器创建后的任何时候,以除迭代器自己的remove或add方法以外的任何方式对列表进行了结构修改,迭代器将抛出ConcurrentModificationException异常。因此,在面对并发修改时,迭代器会快速而干净地失败,而不是在未来不确定的时间发生任意的、不确定的行为。
注意,迭代器的快速失败行为不能得到保证,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬保证。快速失败迭代器尽可能地抛出ConcurrentModificationException。因此,编写一个依赖于此异常的程序是错误的:迭代器的快速失败行为应该只用于检测错误。
这个类是Java集合框架的成员。

 2.LinkedLis的add方法

debug启动

一直下一步,进入node方法 自己是2,他的上一个元素是1,下一个元素没有存,所以是null,

 之前最后一个元素是1,现在新的最后一个元素是2

 指明1的下一个节点就是2,也是就每次添加都添加在尾部

new node的目的就是为了指向上一个节点,下面的l.next就是为了指向下一个节点

3.手写LinkedList

package com.example.list.list;

//手写LinkedList
public class LinkedList<E> {


    private Node<E> first; //第一个节点
    private Node<E> last;//最后一个节点
    int size = 0;//LinkedList存放元素的个数

    private static class Node<E> {
        private E item; //当前结点的值
        private Node<E> prev;//上一个结点
        private Node<E> next;//下一个节点

        /**
         * @param item 当前节点的值
         * @param prev 当前节点的上一个节点
         * @param next 当面结点的下一个节点
         */
        public Node(Node<E> prev, E item, Node<E> next) {
            this.item = item;
            this.prev = prev;
            this.next = next;
        }

    }

    public void add(E e) {
        Node l = last; //获取当前链表中最后一个节点
        //创建一个新的node结点
        Node<E> newNode = new Node<>(l, e, null);//指向上一个节点
        last = newNode;
        if (l == null) {
            //如果在链表中没有最后一个节点,链表是为空
            first = newNode;
        } else {
            l.next = newNode; //指向下一个节点
        }
        size++;


    }

    public E get(int index) {
        //下标如果越界,需要
        return node(index).item;
    }

    Node<E> node(int index) {
        if (index < size >> 1) {
            //查询左边的元素
            Node<E> f = first;
            for (int i = 0; i < index; i++) {
                f = f.next;
            }
            return f;
        } else {
            //查询右边元素
            Node<E> l = last;
            for (int i = size - 1; i > index; i--) {
                l = l.prev;

            }
            return l;
        }
    }

    public E remove(int index) {
        return unlike(node(index));
    }

    private E unlike(Node<E> node) {
        /**
         * 1.根据index,查询出对应的node节点,时间复杂度是O(n)
         * 2.删除链表效率比ArrayList高,
         * 3.获取删除的node节点的上一个和下一个节点
         **/
        final E element = node.item;  //获取到删除的节点的元素
        Node<E> prev = node.prev;  //删除节点的上一个节点
        Node<E> next = node.next; //删除节点的下一个节点
        //如果删除的节点的上一个节点是为空,证明他就是第一个元素
        if (prev == null) {
            //删除的节点是头节点
            first = next;
        } else {
            //删除节点上一个节点.next=删除节点的下一个节点
            prev.next=next;
            next.prev=null;
        }
        //如果删除的节点的下一个节点是null,证明他是尾节点
        if(next==null){
            last=prev;

        }else {
            //如果删除的不是为尾部节点,则删除的下一个节点的.上一个节点改成=删除的上一个节点
            next.prev=prev;
            node.next=null;  //gc回收
        }
        size--;

        return element;
    }

    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("3");
        System.out.println(list.get(0));

    }
}

从手写的,我们很清楚的看 出LinkedList事一个双向链表,在add方法也可以直接看出

4. LinkedList的get方法

debug运行

 折半算法,目前的容量>>1(可以理解为除以2,但是不是完全除以2),如果index比整数小,就去离链表头近的一边去查,反之就去靠近尾部的一边去查

我们这个 从尾部开始查询,如果是去index小于size/2为true,就是从头开始查

当i=2的时候我们就找到了

  我们得到3的删一个元素2

 5.LinkedList的remove方法

根据index删除解读

如果删除对象,他就是把所有元素都遍历一遍效率是很低的,一个一个去比较

6.LinkedList的set方法

看见这个是不是 很眼熟,这个就是我们查询方法,把查询的道节点的值换成你要改的值

查询效率低,当然这个也快不了。

  7.LinkedList总结

1.LinkedList是双向链表的list

2.是非线程安全的

3.元素允许为空,允许重复元素

4.删除效率高,查询效率低(根据index的)

5.没有办法扩容

6.实现了栈和队列的操作方法,因此也可以作为栈、队列和双端队列来使用

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

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

相关文章

全球价值链GVC总出口分解(2011-2014年)

1、数据来源&#xff1a;&#xff29;&#xff23;&#xff29;&#xff2f;数据库 2、时间跨度&#xff1a;2011-2014年 3、区域范围&#xff1a;世界 4、指标说明&#xff1a; 全球价值链分析(Global Value Chain analysis&#xff0c;简称GVC分析)为解决传统贸易统计中…

数据库 1.关系

从关系开始&#xff1a; Table的严格定义&#xff1a; 域就是&#xff1a;学生表{名字&#xff08;char(20),学号(int20)&#xff09;}里面的char20,int20,是用来标记列的数据类型&#xff0c;或者说取值范围的。这个取值范围有一个大小&#xff0c;这个大小就是基数。 就是每种…

世界各国自然资源租金面板数据

1、数据来源&#xff1a;世界银行《世界发展指标数据库》 2、时间跨度&#xff1a;1970-2018年 3、区域范围&#xff1a;全球 4、指标说明&#xff1a; 自然资源租金总额是石油租金、天然气租金、煤炭&#xff08;硬煤和软煤&#xff09;租金、矿产租金和森林租金之和。 …

11.20 至 11.27 五道典型题记录: 贪心 | 应用题 | 脑筋急转弯 | 区间问题 | 双指针

11.20 至 11.27 五道典型题记录&#xff1a; 贪心 | 应用题 | 脑筋急转弯 | 区间问题 | 双指针 松懈了最近&#xff0c;要时刻保持警醒啊&#xff01;学习不能停&#xff0c;说那么多的借口不如花一些心思去学一些知识&#xff0c;之所以学到的内容不成体系&#xff0c;一方面就…

【Java集合】集合是什么?为什么要用集合?

> 集合是什么&#xff1f;为什么要用集合&#xff1f; 保存数据会经常使用到数组&#xff0c;但数组存在以下几个缺陷: 长度开始时必须指定&#xff0c;且一旦指定&#xff0c;不能更改&#xff1b;保存的必须为同一类型的元素&#xff1b;使用数组进行增加元素的步骤比较麻…

MySQL 8.0 Data Dictionary显示

数据字典 对于MySQL的系统库都不会陌生&#xff0c;因为是基本框架&#xff0c;支撑着MySQL有效运行。这些系统库提供诸多功能&#xff0c;如&#xff1a;账号&#xff0c;表&#xff0c;存储过程&#xff0c;表空间&#xff0c;性能监控&#xff0c;配置 等基础信息。系统库目…

【前沿技术RPA】 一文了解UiPath 使用Git管理项目

&#x1f40b;作者简介&#xff1a;博主是一位.Net开发者&#xff0c;同时也是RPA和低代码平台的践行者。 &#x1f42c;个人主页&#xff1a;会敲键盘的肘子 &#x1f430;系列专栏&#xff1a;UiPath &#x1f980;专栏简介&#xff1a;UiPath在传统的RPA&#xff08;Robotic…

【soc】— spluboot校验方法

【soc】— spl/uboot校验方法 一.常规校验/外部有存储介质 针对外部有存储介质的如nandFlash&#xff0c;norFlash&#xff0c;emmc&#xff0c;Sd等&#xff0c;常用的校验方法为&#xff1a;headerspl/uboot header&#xff1a;可定义为结构体&#xff0c;内容包括&#x…

全国366个市县日度空气质量数据(2016-2020年)(AQI,SO2,NO2,PM2.5,PM10)

数据集名称&#xff1a;全国366个市县日度空气质量数据 时间范围&#xff1a;2016-2020年 相关说明&#xff1a;共收录366个市县全年全日数据&#xff0c;其中浓度为日均值&#xff0c;IAQI由浓度推算而来。IAQI为各空气质量指标对应的空气质量指数&#xff0c;用于对应AQI与…

多线程的初识

目录多线程线程的引入进程和线程的关系多线程可能存在的问题多线程程序的创建Thread创建第一个多线程程序线程的抢占式执行查看java进程中的所有线程用Thread的其他方法创建多线程实现Runnable接口使用匿名内部类&#xff0c;继承Thread使用匿名内部类实现Runnable使用Lambda表…

嵌入式Linux驱动开发笔记(未完待续。。。)

一、Git仓库用法 1、linu终端输入下面命令安装 git clone https://e.coding.net/weidongshan/linux_course/linux_basic_develop.git2、 进入到GIT仓库目录 cd /D/abc/doc_and_source_for_mcu_mpu在doc_and_source_for_mcu_mpu目录下&#xff0c;执行以下命令获得资料的最新…

【1752. 检查数组是否经排序和轮转得到】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个数组 nums 。nums 的源数组中&#xff0c;所有元素与 nums 相同&#xff0c;但按非递减顺序排列。 如果 nums 能够由源数组轮转若干位置&#xff08;包括 0 个位置&#xff09;得到&#xf…

appnium环境搭建

一、安装JDK 官网下载对应版本直接安装 二、安装Android SDK 官网下载对应版本直接安装 https://www.androiddevtools.cn/ 三、安装安卓模拟器 我使用的是夜神模拟器&#xff0c;官网下载直接安装 夜神安卓模拟器-安卓模拟器电脑版下载_安卓手游模拟器_手机模拟器_官网 …

springboot整合SpringSecurity并实现简单权限控制

目录 一、SpringSecurity介绍 案例效果&#xff1a; 二、环境准备 2.1 数据库 2.2 项目准备 三、确保项目没问题后开始使用 3.1、Security的过滤链&#xff1a; 3.2、自定义用户名密码登录&#xff1a; 方式1&#xff1a;将用户名密码写在配置文件里 方式2&#xff1a;使…

刷题之莲子的软件工程学和机械动力学以及物理热力学

目录 1、莲子的软件工程学 1&#xff09;题目 2&#xff09;题目解析 3&#xff09;代码 2、莲子的机械动力学 2&#xff09;题目解析 3&#xff09;代码 3、莲子的物理热力学 1&#xff09;、题目 2&#xff09;题目解析 1、莲子的软件工程学 1&#xff09;题目 题目背景…

Linux下的进程控制-进程程序替换

这篇主要说一下Linux下的进程控制中最后一部分内容&#xff1a;进程程序替换。 文章目录1. 进程程序替换1.1 为什么要进程程序替换1.2 替换原理1.3 如何进行程序替换1.3.1 execl函数1.3.2 引入子进程的程序替换1.3.3 execv函数1.3.4 execlp函数和execvp函数1.3.5 如何执行其它…

Flutter自定义对话框返回相关问题汇总

Flutter自定义对话框&#xff0c;禁用系统返回按钮 - WillPopScope 使用WillPopScope即可&#xff0c;重点onWillPop方法: Future<bool> _onWillPop()>new Future.value(false); 由于要弹出dialog&#xff0c;我这里是禁掉返回按钮&#xff0c;当然也可以在这里做一下…

基于SpringBoot的二手商品交易平台

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SpringBoot 前端&#xff1a;Vue、HTML 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#…

3.6.4、随机接入-CSMA/CA协议

无线局域网使用的协议 1、基本概念 对于上述无线局域网为什么 A 和 C 都检测不到对方的无线信号 因为 C 不在 A 的范围内&#xff0c;C 发送无线信号会导致 A 检测不到 C 在发送 对于上述使用广播信道的有线局域网就不会存在这样的问题 总线上某个主机发送的信号&#xff0…

JVM虚拟机字节码执行引擎——类文件和类加载之前必看

文章目录虚拟机字节码执行引擎运行时栈帧结构局部变量表&#xff08;Local Variables&#xff09;操作数栈动态链接&#xff08;Dynamic Linking&#xff09;方法返回地址附加信息方法调用解析分派虚方法和非虚方法普通调用指令&#xff1a;动态调用指令&#xff1a;动态类型语…