【JAVA】双向链表详解

news2024/10/7 2:28:30

【JAVA】双向链表详解

  • 双向链表的定义
  • 双向链表的初步实现(准备)
  • 双向链表的操作
  • 一. 打印链表
  • 二. 得到链表长度
  • 三. 插入操作
    • 3.1 头插法
    • 3.2 尾插法
    • 3.3 任意位置插入
  • 四. 删除操作
    • 4.1 删除第一次出现为key的节点(3种情况)
    • 4.2 删除所以值为key的节点(3种情况)
  • 五. 清空双向链表

双向链表的定义

LinkedList的底层是双向链表结构(链表后面介绍),由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。

每个数据节点都有两个指针,指向前驱和后继,所以,双向链表中的任意一个节点开始,都可以十分方便找到前驱节点和后继节点。
在这里插入图片描述

双向链表的初步实现(准备)

static class ListNode{
        private int val;//值
        private ListNode prev;//前驱
        private ListNode next;//后继

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

    public ListNode head;//双向链表的头节点
    public ListNode last;//双向链表的尾节点

双向链表的操作

一. 打印链表

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

二. 得到链表长度

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

三. 插入操作

3.1 头插法

当我们想把新的结点插入到第一个结点位置处,可以先建立一个结点,然后把头结点的prev变为我们新建立结点的next值,然后将我们新建立的结点值变为null,最后将头结点指向新的插入的结点。

在这里插入图片描述

注意: 我们需要首先判断这个链表是否为空,假如为空就直接构建链表即可。

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

3.2 尾插法

尾插法顾名思义就是从结尾插入新的结点,这个和头插法过程差不多,只不过一个是改变head的位置,一个是改变last的位置。

和头插法一样,这个同样需要判断链表是否初始为空。

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=last.next;
        }
    }

3.3 任意位置插入

  • 这个是最复杂的一种插入方式,我们需要先找到需要插入位置的结点cur,然后利用cur就可以得出前后两个结点,直接插入即可。
  • 首先我们建立一个方法来查找cur的位置,一个返回值为结点的元素。
  • 注意插入的先后顺序。

在这里插入图片描述

public void addIndex(int index,int data){
        //为头插
        if(index==0){
            addFirst(data);
            return;
        }
        //为尾插
        if(index==size()){
            addLast(data);
            return;
        }
        //任意位置插入
        ListNode cur=searchIndex(index);//找要插入的位置
        ListNode node=new ListNode(data);
        node.next=cur;
        cur.prev.next=node;
        node.prev=cur.prev;
        cur.prev=node;
    }
    public ListNode searchIndex(int index){
        ListNode cur=head;
        while(index!=0){
            cur=cur.next;
            index--;
        }
        return cur;
    }

四. 删除操作

4.1 删除第一次出现为key的节点(3种情况)

假如是头结点的话我们还需要判断这个链表是否只有一个结点,如果是那么last指针也会为空,head指针也会为空,否则,我们只移动头指针结点就可以。
在这里插入图片描述

//删除第一次出现关键字key的节点,一共三种情况
    public void remove(int key){
        ListNode cur = head;
        while (cur != null) {
            if(cur.val == key) {
                //1.当删除头节点
                if(cur == head) {
                    head = head.next;
                    //1.1当头指针不为空时
                    if(head != null) {
                        //考虑只有一个节点的情况下
                        head.prev = null;
                    }else {
                        //1.2头指针为空时
                        last = null;
                    }
                }else {
                    //2.删除中间节点 和  3.尾巴节点
                    if(cur.next != null) {
                        //删除中间节点
                        cur.prev.next = cur.next;
                        cur.next.prev = cur.prev;
                    }else {
                        //尾巴节点
                        cur.prev.next = cur.next;
                        last = last.prev;
                    }
                }
                return;
            }else {
                cur = cur.next;
            }
        }
    }

4.2 删除所以值为key的节点(3种情况)

//删除所以值为key的节点
    public void removeAllKey(int key){
        ListNode cur = head;
        while (cur != null) {
            if(cur.val == key) {
                //删除头节点
                if(cur == head) {
                    head = head.next;
                    if(head != null) {
                        //考虑只有一个节点的情况下
                        head.prev = null;
                    }else {
                        last = null;
                    }
                }else {
                    //删除中间节点 和  尾巴节点
                    if(cur.next != null) {
                        //删除中间节点
                        cur.prev.next = cur.next;
                        cur.next.prev = cur.prev;
                    }else {
                        //尾巴节点
                        cur.prev.next = cur.next;
                        last = last.prev;
                    }
                }
                cur=cur.next;
            }else {
                cur = cur.next;
            }
        }
    }

五. 清空双向链表

public void clear(){
        ListNode cur=head;
        while(cur!=null){
            ListNode curNext=cur.next;//保存cur.next。
            cur.prev=null;
            cur.next=null;
            cur=curNext;
        }
        //最后置空
        head=null;
        last=null;
    }

💓
感谢阅读!

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

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

相关文章

Vue--》Vue3打造可扩展的项目管理系统后台的完整指南(四)

今天开始使用 vue3 ts 搭建一个项目管理的后台,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行&…

保姆级别ps bate版本下载

前言:最近的ps bete版本在抖音也是上了热搜,时不时就能刷到一个,相信大家也知道ai带来的魅力,真的很强,那我们就开始安装教程吧。 ​过程: 先打开链接:Adobe Creative Cloud | Details and pr…

使用外部工具横向移动

Smbexe、Psexec Psexec PsExec是一种轻巧的telnet代替品,可让您在其他系统上执行进程,并为控制台应用提供完整的交互性,无需手动安装客户端软件。 原理: 1、ipc$连接,释放Psexesvc.exe 2、OpenSCManager打开受害者…

如何使用ChatGPT自带插件

OpenAI的插件将ChatGPT连接到第三方应用程序。这些插件使ChatGPT能够与开发者定义的API进行交互,增强ChatGPT的能力,并使其能够执行广泛的操作。插件使ChatGPT能够做如下事情: 获取实时信息;例如,体育比分&#xff0c…

采样率(压缩比)对OMP算法的影响

前面详细分析了OMP重构算法原理以及实现,本篇主要分析采样率对OMP算法的影响。 OMP重构算法的流程为 以下分析采样率对OMP算法的影响。 先对一维信号重构进行分析,表1是OMP算法中采样率对重构的MSE和时间的对应表格: 表1:MP算法采…

04-Springbooot与Spring Cloud Alibaba搭建后端架构

1、创建Springbooot父工程 1.1、使用快速创建Springbooot工程的方式: 1.2、项目使用Maven进行管理 settings.xml,配好了阿里镜像 02-maven的安装配置_NikoWord的博客-CSDN博客 2、项目初始化配置 01-IDEA使用技巧_NikoWord的博客-CSDN博客 04-设置…

VS2010 C语言DLL项目hello world程序以及win32控制台程序调用dll示例

一、使用Visual Studio 2010编写C语言 DLL项目hello world程序 1.点击桌面 VS2010 图标,运行程序。(或者通过菜单栏打开程序) 2.点击【文件】 -> 【新建】 -> 【项目】 3.点击【VisualC】和【win32控制台应用程序】,设置好名称和存储位置&#xf…

白盒测试方法

为什么要进行白盒测试? 如果所有软件错误的根源都可以追溯到某个唯一原因,那么问题就简单了。然而,事实上一个bug 常常是由多个因素共同导致的,如下图所示。 黑盒查不到的问题 假设此时开发工作已结束,程序送交到测试…

飞腾FT2000实战开发-GPIO的配置

目录 环境: 飞腾GPIO介绍: 临时配置: 永久配置: 环境: CPU:FT2000(64位,四核) 操作系统:linux-4.4.131-20200710 内核:kylin4.0.2 飞腾GPIO介绍&#x…

JavaScript创建二维数组踩坑记录

需求:创建一个m*n且元素值为0的二维数组 碎碎念 1、 今天刷Leetcode时,遇见一个这样的需求,机智如我,定然不会通过双重for循环来创建,于是,我写了这样一行代码 const dimensionalArray new Array(m).fi…

Spring Boot 加载自定义配置文件

文章目录 一、为什么需要加载自定义配置文件二、使用PropertySource加载自定义配置文件(一)创建Spring Boot项目(二)创建自定义配置文件(三)创建自定义配置类(四)编写测试方法&#…

硅谷甄选 Blog_01-搭建后台管理系统模板

搭建后台管理系统模板分为两大步骤: 项目初始化项目配置 项目初始化 环境准备 node:v16.16.0pnpm:v7.22.0 初始化项目 全局安装pnpm指令: npm i -g pnpm项目初始化指令: pnpm create vite如下图所示进行项目的…

嵌入式BSP工程师基本任务分析

到底什么是BSP工程师呢?来看这篇文章吧 一、嵌入式系统 要明白什么是嵌入式软件工程师,我们先从嵌入式系统(嵌入式设备)说起。维基百科上对嵌入式系统的定义如下: 嵌入式系统(Embedded System&#xff0…

5 个强大的 HTML5 API

HTML5提供了一些非常强大的JavaScript和HTML API,来帮助开发者构建精彩的桌面和移动应用程序。本文将介绍5个新型的API,希望对你的开发工作有所帮助。 1. 全屏API(Fullscreen API) 该API允许开发者以编程方式将Web应用程序全屏运…

1_标准IO

目录 标准I/O一、概念二、特点⭐⭐⭐三、缓冲区⭐⭐⭐3.1 全缓冲3.1 行缓冲3.3 不缓冲 四、函数接口⭐⭐⭐⭐4.1 打开4.1.1 fopen4.1.2 freopen4.1.2 容错机制perror 4.2 关闭4.2.1 fclose4.3 读写操作4.3.1 字符I/O4.3.2 行I/O4.3.3 块I/O 4.4 定位操作4.5 文件结束和错误 标准…

多维时序 | MATLAB实现NARX非线性自回归外生模型多变量多步时间序列预测(电池预测模型)

多维时序 | MATLAB实现NARX非线性自回归外生模型多变量多步时间序列预测(电池预测模型) 目录 多维时序 | MATLAB实现NARX非线性自回归外生模型多变量多步时间序列预测(电池预测模型)效果一览基本介绍模型描述程序设计参考资料效果一览 基本介绍 多维时序 | MATLAB实现NARX非…

CSDN 周赛 56 期

CSDN 周赛 56 期 1、题目名称:因数-数字游戏骗分抛出异常考试时代码 2、题目名称:津津的储蓄计划3、题目名称:一维数组的最大子数组和4、题目名称:莫名其妙的键盘小结 1、题目名称:因数-数字游戏 小Q的柠檬汁做完了。 …

为视图增加权重以调整基本线性布局

乍看上去线性布局LinearLayout很基础,不太灵活,毕竟其只是按照某种顺序摆放视图。但是还可以使用另外一些属性调整布局的外观。 编写一个不太一样的布局。这个布局让按钮显示在布局的右下角,其余全部空间由一个可编辑文本域占据。 一个基本线…

算法套路十九——树形DP

算法套路十九——树形DP 树形 DP,即在树上进行的 DP。由于树固有的递归性质,这里的DP是指是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法,故虽然带有DP,但一般都是通过递归来进行。 算法示例一:…

centos7使用docker compose部署ELK

说明:1、一定要先不要配置那么多配置文件,去除掉一些,先让docker compose启动相关服务能访问的时候,使用拷贝方法,把相关的配置文件拷贝出来在外面修改,这样保险一些,不然容易配置文件错误无法启…