LinkedList的顶级理解

news2024/9/25 19:16:16

目录

1.LinkedList的介绍

LinkedList的结构

2.LinkedList的模拟实现

2.1创建双链表 

2.2头插法

2.3尾插法

2.4任意位置插入

2.5查找关键字

2.6链表长度

2.7遍历链表

2.8删除第一次出现关键字为key的节点

2.9删除所有值为key的节点

2.10清空链表

2.11完整代码

3.LinkedList的使用 

3.1LinkedList的构造

3.2LinkedList的其他常用方法介绍 

 3.3LinkedList的遍历

3.4ArrayList和LinkedList的区别


1.LinkedList的介绍

LinkedList的底层是双向链表结构,元素存储在单独的节点中,通过引用将节点连接起来了。

如果对双向链表或链表不太清晰,可以先看看本博主写的有关链表的文章。

链表的顶级理解_WHabcwu的博客-CSDN博客

在集合框架中,LinkedList也实现了List接口,具体如下:

注意: 

1. LinkedList 实现了 List 接口
2. LinkedList 的底层使用了双向链表
3. LinkedList 没有实现 RandomAccess 接口,因此 LinkedList 不支持随机访问
4. LinkedList 的任意位置插入和删除元素时效率比较高,时间复杂度为 O(1)
5. LinkedList 比较适合任意位置插入的场景

 

LinkedList的结构

 

  • 前驱节点:用于存储前一节点的位置,用prev表示
  • 后继节点:用于储存下一节点的位置,用next表示
  • 所需要储存的数据,用val表示
  • 头节点:用head表示
  • 尾节点:用last表示

2.LinkedList的模拟实现

无非是增删查改,在某位置的插入与删除,对数据内容进行管理和操作。

具体实现内容:

(1)创建双链表

(2)头插法

(3)尾插法

(4)任意位置插入

(5)查找关键字

(6)链表长度

(7)遍历链表

(8)删除第一次出现关键字为key的节点

(9)删除所有值为key的节点

(10)清空链表

2.1创建双链表 

public class MyLinkedList {
    static class ListNode {
        public int val;
        public ListNode prev;//前驱
        public ListNode next;//后继

        public ListNode(int val) {
            this.val = val;
        }
    }

    public ListNode head;//头节点
    public ListNode last;//尾节点
}

2.2头插法

(1)首先判断头节点是否为null若为null,则该节点就是头节点,也是尾节点.

(2)头节点不为null,将原先head的前驱节点指向新增节点位置,新增节点后驱节点指向head节点的位置。

(3)head指向新增节点位置。

    //插法 O(1)
    public void addFirst(int data){
        ListNode node = new ListNode(data);
        if(head == null) {
            head = node;
            last = node;
        }else {
            node.next = head;
            head.prev = node;
            head = node;
        }
    }

2.3尾插法

与头插法大同小异

    //尾插法 O(1)
    public void addLast(int data){
        ListNode node = new ListNode(data);
        if(head == null) {
            head = node;
            last = node;
        }else {
            last.next = node;
            node.prev = last;
            last = node;
        }
    }

2.4任意位置插入

需要插入的位置必须为合法,如果不合法,我们会抛出一个异常进行提醒

public class ListIndexOutOfException extends RuntimeException{
    public ListIndexOutOfException() {
    }

    public ListIndexOutOfException(String message) {
        super(message);
    }
}

任意位置插入,我们可以分为种情况,插在开头,插在结尾,插在中间

    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        if(index < 0 || index > size()) {
            throw new ListIndexOutOfException("违规数据");
        }
        if(index == 0) {
            addFirst(data);
            return;
        }
        if(index == size()) {
            addLast(data);
            return;
        }

        ListNode cur = findIndex(index);
        //
        ListNode node = new ListNode(data);
        cur.prev.next = node;
        node.next = cur;
        node.prev = cur.prev;
        cur.prev = node;

    }

2.5查找关键字

直接遍历查找即可

    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        ListNode cur = head;
        while (cur != null) {
            if(cur.val == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

2.6链表长度

用一个len变量进行记录,遍历链表

    public int size(){
        int len = 0;
        ListNode cur = head;
        while (cur != null) {
            len++;
            cur = cur.next;
        }
        return len;
    }

2.7遍历链表

    public void display(){
        ListNode cur = head;
        while (cur != null) {
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }

2.8删除第一次出现关键字为key的节点

(1)一个节点都没有
(2)删除数据在第一个
(3)没有你要删除的数据
(4)有你要删除的数据且不是第一个

(5)删除数据最后一个

 找到就return;

    //删除第一次出现关键字为key的节点
    public void remove(int key){
        ListNode cur = head;
        while (cur != null) {
            //开始删除了
            if(cur.val == key) {
                //1. 删除的是头节点
                if(cur == head) {
                    head = head.next;
                    //只有一个节点
                    if(head != null) {
                        head.prev = null;
                    }
                }else {
                    //中间  尾巴
                    cur.prev.next = cur.next;
                    //不是尾巴节点
                    if(cur.next != null) {
                        cur.next.prev = cur.prev;
                    }else {
                        //是尾巴节点
                        last = last.prev;
                    }
                }
                return;
            }
            cur = cur.next;
        }
    }

2.9删除所有值为key的节点

与删除第一次出现关键字为key的节点几乎是一模一样的;

我们只需要遍历完就好,只需要return删掉就好。

    //删除所有值为key的节点
    public void removeAllKey(int key){
        ListNode cur = head;
        while (cur != null) {
            //开始删除了
            if(cur.val == key) {
                //1. 删除的是头节点
                if(cur == head) {
                    head = head.next;
                    //只有一个节点
                    if(head != null) {
                        head.prev = null;
                    }
                }else {
                    //中间  尾巴
                    cur.prev.next = cur.next;
                    //不是尾巴节点
                    if(cur.next != null) {
                        cur.next.prev = cur.prev;
                    }else {
                        //是尾巴节点
                        last = last.prev;
                    }
                }
            }
            cur = cur.next;
        }
    }

2.10清空链表

只需要遍历整个链表,将每个节点的前驱与后继节点都置为null就好

    public void clear(){
        ListNode cur = head;
        while(cur != null) {
            cur.prev  = null;
            cur = cur.next;
            cur.prev.next = null;
        }
        head = null;
        last = null;
    }

2.11完整代码

public class MyLinkedList {
    static class ListNode {
        public int val;
        public ListNode prev;//前驱
        public ListNode next;//后继

        public ListNode(int val) {
            this.val = val;
        }
    }

    public ListNode head;//头节点
    public ListNode last;//尾节点

    //头插法 O(1)
    public void addFirst(int data){
        ListNode node = new ListNode(data);
        if(head == null) {
            head = node;
            last = node;
        }else {
            node.next = head;
            head.prev = node;
            head = node;
        }
    }
    //尾插法 O(1)
    public void addLast(int data){
        ListNode node = new ListNode(data);
        if(head == null) {
            head = node;
            last = node;
        }else {
            last.next = node;
            node.prev = last;
            last = node;
        }
    }
    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        if(index < 0 || index > size()) {
            throw new ListIndexOutOfException("违规数据");
        }
        if(index == 0) {
            addFirst(data);
            return;
        }
        if(index == size()) {
            addLast(data);
            return;
        }

        ListNode cur = findIndex(index);
        //
        ListNode node = new ListNode(data);
        cur.prev.next = node;
        node.next = cur;
        node.prev = cur.prev;
        cur.prev = node;

    }
    private ListNode findIndex(int index) {
        ListNode cur = head;
        while (index != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        ListNode cur = head;
        while (cur != null) {
            if(cur.val == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
    //删除第一次出现关键字为key的节点
    public void remove(int key){
        ListNode cur = head;
        while (cur != null) {
            //开始删除了
            if(cur.val == key) {
                //1. 删除的是头节点
                if(cur == head) {
                    head = head.next;
                    //只有一个节点
                    if(head != null) {
                        head.prev = null;
                    }
                }else {
                    //中间  尾巴
                    cur.prev.next = cur.next;
                    //不是尾巴节点
                    if(cur.next != null) {
                        cur.next.prev = cur.prev;
                    }else {
                        //是尾巴节点
                        last = last.prev;
                    }
                }
                return;
            }
            cur = cur.next;
        }
    }
    //删除所有值为key的节点
    public void removeAllKey(int key){
        ListNode cur = head;
        while (cur != null) {
            //开始删除了
            if(cur.val == key) {
                //1. 删除的是头节点
                if(cur == head) {
                    head = head.next;
                    //只有一个节点
                    if(head != null) {
                        head.prev = null;
                    }
                }else {
                    //中间  尾巴
                    cur.prev.next = cur.next;
                    //不是尾巴节点
                    if(cur.next != null) {
                        cur.next.prev = cur.prev;
                    }else {
                        //是尾巴节点
                        last = last.prev;
                    }
                }
            }
            cur = cur.next;
        }
    }

    public int size(){
        int len = 0;
        ListNode cur = head;
        while (cur != null) {
            len++;
            cur = cur.next;
        }
        return len;
    }

    public void display(){
        ListNode cur = head;
        while (cur != null) {
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }

    public void clear(){
        ListNode cur = head;
        while(cur != null) {
            cur.prev  = null;
            cur = cur.next;
            cur.prev.next = null;
        }
        head = null;
        last = null;
    }
}

3.LinkedList的使用 

3.1LinkedList的构造

3.2LinkedList的其他常用方法介绍 

 

 3.3LinkedList的遍历

    public static void main(String[] args) {
        LinkedList<Integer> linkedList = new LinkedList<>();
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        linkedList.add(4);
        linkedList.add(5);
        // foreach遍历
        for (int e:list) {
            System.out.print(e + " ");
        }
        System.out.println();
        System.out.println("=====================");
        // 使用迭代器遍历---正向遍历
        Iterator<Integer> iterator1 = linkedList.iterator();
        while(iterator1.hasNext()){
            System.out.println(iterator1.next());
        }
        System.out.println("=====================");
        // 使用反向迭代器---反向遍历
        ListIterator<Integer> iterator2 = linkedList.listIterator(linkedList.size());
        while (iterator2.hasPrevious()){
            System.out.println(iterator2.previous());
        }
    }

3.4ArrayList和LinkedList的区别

 


以上为我个人的小分享,如有问题,欢迎讨论!!! 

都看到这了,不如关注一下,给个免费的赞 

 

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

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

相关文章

PowerJob容器的使用(创建一个外置动态加载的任务)

1.使用容器的模板生成功能 2. 解压导入到IDEA中&#xff0c;下载依赖&#xff0c;添加处理器 3. 打包成jar 4. 上传项目到容器 5. 启动容器--部署jar 6. 复制一份上篇文章写的测试单机执行的任务实例&#xff0c;把执行配置修改从外置&#xff08;动态加载&#xff09; &…

scratch计算圆的面积和周长 2023年5月中国电子学会图形化编程 少儿编程 scratch编程等级考试四级真题和答案解析

目录 scratch计算圆的面积和周长 一、题目要求 1、准备工作 2、功能实现 二、案例分析

vue 简单实验 自定义组件 传参数 props

1.代码 <script src"https://unpkg.com/vuenext" rel"external nofollow" ></script> <div id"todo-list-app"><todo-item v-bind:todo"todo1"></todo-item> </div> <script> const ListR…

IIS短文件泄漏漏洞修改

升级netFramework至4.0以上版本 2.关闭Web服务扩展- ASP.NET&#xff08;不使用的可以关闭&#xff09; 3.CMD关闭NTFS 8.3文件格式的支持&#xff08;1代表关闭&#xff0c;0代表开启&#xff09; 不同系统关闭命令稍有区别&#xff0c;该功能默认是开启的&#xff0c;对于大多…

Rust之自动化测试(一):如何编写测试

开发环境 Windows 10Rust 1.71.1 VS Code 1.81.1 项目工程 这里继续沿用上次工程rust-demo 编写自动化测试 Edsger W. Dijkstra在他1972年的文章《谦逊的程序员》中说&#xff0c;“程序测试可以是一种非常有效的方法来显示错误的存在&#xff0c;但它对于显示它们的不存在…

用python从零开始做一个最简单的小说爬虫带GUI界面(2/3)

目录 前一章博客 前言 主函数的代码实现 逐行代码解析 获取链接 获取标题 获取网页源代码 获取各个文章的链接 函数的代码 导入库文件 获取文章的标题 获取文章的源代码 提取文章目录的各个文章的链接 总代码 下一章内容 前一章博客 用python从零开始做一个最简单…

软考高项(九)项目范围管理 ★重点集萃★

&#x1f451; 个人主页 &#x1f451; &#xff1a;&#x1f61c;&#x1f61c;&#x1f61c;Fish_Vast&#x1f61c;&#x1f61c;&#x1f61c; &#x1f41d; 个人格言 &#x1f41d; &#xff1a;&#x1f9d0;&#x1f9d0;&#x1f9d0;说到做到&#xff0c;言出必行&am…

这样才能玩转Linux内核之CPU篇

哈喽&#xff0c;我是子牙&#xff0c;一个很卷的硬核男人 深入研究计算机底层、Windows内核、Linux内核、Hotspot源码……聚焦做那些大家想学没地方学的课程。为了保证课程质量及教学效果&#xff0c;一年磨一剑&#xff0c;三年先后做了三个课程&#xff1a;手写JVM、手写OS及…

【AutoLayout案例04-游戏图片-按钮适配 Objective-C语言】

一、好,我们再看一个案例, 刚才,这个案例, 这么一个案例 这个案例,是什么意思呢, 这里给大家做一个3.5英寸、4.0英寸的屏幕适配, 因为我们这里图片,只有一个,就是4英寸的这么一个图片 什么意思呢,要求我们在3.5英寸的屏幕、和4英寸的屏幕的时候,都能正常显示这个图…

从零开始的Hadoop学习(一) | 大数据概念、特点、应用场景、发展前景

1. 大数据概念 大数据(Big Data)&#xff1a;指 无法在一定时间范围 内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的 海量、高增长率和多样化 的 信息资产。 大数据主要解决&#xff0c;海量…

创新生物药-创新药物研发-发展趋势分析(一文看懂)

随着科技的不断进步和生物医学领域的快速发展&#xff0c;生物创新药研发成为了推动医学进步和改善人类健康的重要领域。目前生物药包含了蛋白类药物、基因疗法、抗原、细菌、病毒、真菌、酵母、生物类似药、外泌体药物、免疫疗法、可溶性受体、克隆技术、微生物技术等药物&…

【Cortex-M3权威指南】学习笔记1 - 概览与基础

介绍 三种主流 Cortex 款式 款式 A&#xff1a;设计用于高性能的“开放应用平台” 款式 R&#xff1a;用于高端的嵌入式系统&#xff0c;尤其是那些带有实时要求的 款式 M&#xff1a;用于深度嵌入的&#xff0c;单片机风格的系统中 指令集发展 ARM 处理器一直支持两种形式上…

10个最好的云GPU服务

随着深度学习、人工智能和机器学习等新技术的出现&#xff0c;云 GPU 的需求量很大。 GPU&#xff08;图形处理单元&#xff09;是专用处理器&#xff0c;用于处理计算机图形和游戏等活动所需的大量数据集和复杂计算。不过&#xff0c;它们现在对人工智能&#xff08;A.I.&…

我们在深圳聊了聊娱乐产品怎么“玩”!

伴随着移动互联网的普及&#xff0c;国内娱乐社交产品呈现出多元化发展趋势。 根据相关调研显示&#xff0c;一般普通用户通常会同时选择至少 3 款同类娱乐社交应用作为日常休闲、社交工具。可以说&#xff0c;各类垂直赛道聚集了大量新老“玩家”。 在如此激烈的竞争环境下&am…

Openlayers实战:启动、取消事件的监测

在Openlayers的实际项目中,我们会用到各种地图事件,比如click,dblclick,change,loadstart … 监测的时候往往用on(‘事件名称’,回调函数)来操作,但是取消这些事件的监控怎么做呢,请参考源代码。 效果图 源代码 /* * @Author: 大剑师兰特(xiaozhuanlan),还是大剑师…

Java百度提前批面试题

今天分享百度提前批的 Java 后端开发面经&#xff0c;整体上考察的点挺多的&#xff0c;主要重点考察了网络i/o、网络协议、linux系统、mysql&#xff0c;Java 问的不多&#xff0c;可能是百度的后端开发的语言不是主要以 Java 为主&#xff0c;所以重点看面试者的计算机基础是…

删除重复记录但保留其中一行数据的sql写法

欢迎关注微信公众号&#xff1a;互联网全栈架构 数据库表中存在重复记录的场景并不罕见&#xff0c;导致这种情况的原因可能是进行了数据迁移&#xff0c;或者程序代码有bug&#xff08;比如并发情况没有处理好&#xff09;&#xff0c;或者在测试库中手动插入了重复数据&#…

问道管理:证券代码是什么?有什么用?

交流炒股经历时&#xff0c;有些股民一时忘了股票发行公司的全称&#xff0c;会直接报一串数字来代替&#xff0c;这串数字的内容是证券代码&#xff0c;那么&#xff0c;证券代码是什么&#xff1f;它又起什么作用&#xff1f;关于这些&#xff0c;为大家准备了以下参考内容。…

Python-主线程控制子线程-4

需求&#xff1a;在Python-主线程控制子线程-3的基础上&#xff0c;新增使用UDP接收指令功能&#xff0c;代替从键盘输入指令 # 修改后的程序&#xff0c;主线程可以获取子线程的结果 import threading import time import queue import tracebackfrom loguru import logger i…

齐聚众力,中国移动以“百川”定乾坤

近日&#xff0c;由工业和信息化部、宁夏回族自治区人民政府主办的2023中国算力大会在宁夏银川举办。中国移动党组书记、董事长杨杰参加开幕式&#xff0c;并在大会主论坛作题为《算网筑基锻引擎 数实融合创未来》的主旨演讲。在演讲中&#xff0c;杨杰表示&#xff1a;未来&am…