[算法通关村] 1.2 链表的插入

上一节我们谈到了链表的概念,以及链表的创建方法,忘记的小伙伴可以复习一下:

[算法通关村] 1.1 单向链表的创建


        今天我们来探究一下链表的插入,链表的插入共有 3 种可能性,分别是在链表的头部插入、在中间插入,和在链表的尾部插入(追加),不同的插入位置对应着不同的代码,所以需要一个一个来探究。 

在链表的中间插入

        我们先来看一个新节点 nodeInsert 如何插入到位置为 1 < k < n+1 的原节点前面。(n 为链表长度)

        不难想到,由于我们上一节中创建的是一个 “单向链表”,每一个节点仅知道下一个节点的位置,并不知道上一个节点的位置,就像 “猴子掰玉米” 一样。在插入过程中,为了不丢失节点,需要保证每一个节点都被引用(指向),才不会被 JVM 回收,我们可以看到如下的插入过程:

         首先需要将 nodeInsert.next 指向拟插入位置 k 的上一个节点的 next,即:

nodeInsert.next = current.next

        然后将 current.next 指向 nodeInsert,此时变量 current 指向节点的原 next 关系自动消失:(只能同时指向一个后继节点)

current.next = nodeInsert

在链表的头部插入

        在链表的头部插入需要移动头指针 head 。由于头插移动了头结点,内存地址发生变化,所以需要将返回的新节点赋与 linkedList,否则后续计算会出错。

        首先将待插入节点 nodeInsert 的 next 变量指向头结点,然后移动头指针指向 nodeInsert 即可:

        代码实现如下:

nodeInsert.next = linkedList;
linkedList = nodeInsert;
return linkedList;

//上面 return 还可以这么写:
//return nodeInsert;

在链表的尾部插入

        在链表的尾部插入主要有两步,首先需要一个指针(Node 型变量)指向尾结点,这就涉及到了链表的遍历,而在 “链表的中间插入” 环节,也会涉及到链表的遍历,我们可以将此代码复用:

// 移动指针到拟插入位置的前一个节点
int count = 1;
while (count < position - 1) {
    current = current.next;
    count++;
}

        然后只需要将尾结点 current.next 指向待插入的 nodeInsert 节点即可:

// 此代码可省略,实际上是赋予了 null 值
// 因无伤大雅,又与 “中间插入” 代码一致,故可复用
nodeInsert.next = current.next;

current.next = nodeInsert;

        插入过程的图形化展示如下:

注意事项及完整代码

         上述原理很容易理解,但在实际操作中,还需要判断插入位置是否越界,即:

  • 最少在 position = 1 前插入(头部插入)
  • 至多在 position = getLength(linkedList) + 1 前插入(尾部插入)

        当插入位置 position 的值不满足上述要求时,我们会手动抛出一个异常:

// 短路或 先判断简单的
if (position < 1 || position > (getLength(linkedList) + 1)) {
            throw new Exception("参数:拟插入位置 越界");
        }

        其次,我们还需要查看待操作链表是否为一个空链表,这在方法 getLength 中就会进行判断,所以无需重复写判空语句:

public static int getLength(NewNode linkedList) throws Exception {
    int length = 0;
    NewNode current = linkedList;
    while (current != null) {
        length++;
        current = current.next;
    }
    if (length == 0) {
        throw new Exception("链表不存在");
    }
    return length;
}

        除此之外,还实现了 toString 方法用于遍历链表查看效果,该方法不是必须的。最后给出完整代码:

class NewNode {

    public int val;
    public NewNode next;

    NewNode(int val) {
        this.val = val;
        this.next = null;
    }
}

public class BasicLinkList {

    /**
     * 链表插入
     *
     * @param linkedList 链表头节点
     * @param nodeInsert 待插入节点
     * @param position   在该位置前插入
     * @return 插入后得到的新链表(指向头节点)
     */
    public static NewNode insertNode(NewNode linkedList, NewNode nodeInsert, int position) throws Exception {
        // 越界判断:
        //   最少在 position = 1 前插入(头插),
        //   最多在 position = getLength(linkedList) + 1 前插入(尾插)
        // 短路或 先判断简单的
        if (position < 1 || position > (getLength(linkedList) + 1)) {
            throw new Exception("参数:拟插入位置 越界");
        }

        //在链表开头插入
        if (position == 1) {
            nodeInsert.next = linkedList;
//            return nodeInsert;
            //上面return还可以这么写:
            linkedList = nodeInsert;
            return linkedList;
        }

        NewNode current = linkedList;
        int count = 1;
        // 移动指针到拟插入位置的前一个节点
        while (count < position - 1) {
            current = current.next;
            count++;
        }
        nodeInsert.next = current.next;
        current.next = nodeInsert;

        return linkedList;
    }

     /**
     * 获取链表长度
     *
     * @param linkedList 链表头节点
     * @return 链表长度
     */
    public static int getLength(NewNode linkedList) throws Exception {
        int length = 0;
        NewNode current = linkedList;
        while (current != null) {
            length++;
            current = current.next;
        }
        if (length == 0) {
            throw new Exception("链表不存在");
        }
        return length;
    }

    /**
     * 输出链表
     *
     * @param head 头节点
     */
    public static String toString(NewNode head) {
        NewNode current = head;
        StringBuilder stringBuilder = new StringBuilder();
        while (current != null) {
            stringBuilder.append(current.val).append("\t");
            current = current.next;
        }
        return stringBuilder.toString();
    }

    public static void main(String[] args) throws Exception {

        // 先创建一个链表
        NewNode linkedList = BasicLink.initLinkedList(new int[]{1, 2, 3, 4, 5});

        NewNode newNode;

        // 中间插入节点:在第 3 个节点前,插入 val = 30
        newNode = new NewNode(30);
        System.out.println(BasicLinkList.toString(BasicLinkList.insertNode(linkedList, newNode, 3)));
        System.out.println("========");
        // 头部插入节点:插入 val = 72
        newNode = new NewNode(72);
        // 由于头插移动了头结点,内存地址发生变化,所以需要将返回的新节点赋与 linkedList,否则后续计算会出错
        linkedList = BasicLinkList.insertNode(linkedList, newNode, 1);
        System.out.println(BasicLinkList.toString(linkedList));
        System.out.println("========");
        // 尾部插入节点:插入 val = 9
        newNode = new NewNode(9);
        System.out.println(BasicLinkList.toString(BasicLinkList.insertNode(linkedList, newNode, BasicLinkList.getLength(linkedList)+1)));
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Cilium

Cilium是一个开源的、面向Kubernetes和容器环境的网络插件&#xff0c;用于提供高级的网络和安全功能。它是一个用于容器网络和网络层四、七层安全的项目&#xff0c;旨在简化网络和安全层的管理&#xff0c;并提供高性能和低延迟的数据包处理。Cilium通过BPF&#xff08;Berke…

UE5 用DLL文件制作第三方插件

本篇博文介绍了&#xff0c;如果在UE 中如何使用第三方库&#xff0c;及制作成插件的方法。 DLL 文件是上篇文章中创键的具体的方法见上篇文章。下面开始介绍方法 首先&#xff0c;创建一个空白的 UE5 C 项目&#xff0c;然后再创建一个空白内容的插件&#xff0c;如下图所示 …

STM32MP157驱动开发——按键驱动(线程化处理)

文章目录 “线程化处理”机制&#xff1a;内核函数线程化处理方式的按键驱动程序(stm32mp157)编程思路button_test.cgpio_key_drv.cMakefile修改设备树文件编译测试 “线程化处理”机制&#xff1a; 工作队列是在内核的线程的上下文中执行的 工作队列中有多个 work&#xff0…

【TypeScript】类型推断与类型别名的使用方式。

什么是类型推断&#xff1f; 在 TypeScript 中&#xff0c; 如果声明变量时&#xff0c;没有明确的指定类型&#xff0c;那么 TypeScript 会依照类型推论&#xff08;Type Inference&#xff09;的规则推断出一个类型。 以下代码虽然没有明确指定类型&#xff0c;但是会在编译的…

【043】解密C++ STL:深入理解并使用 list 容器

解密C STL&#xff1a;深入理解并使用list容器 引言一、list 容器概述二、list容器常用的API2.1、构造函数2.2、数据元素插入和删除操作2.3、大小操作2.4、赋值操作2.5、数据的存取2.6、list容器的反转和排序 三、使用示例总结 引言 &#x1f4a1; 作者简介&#xff1a;一个热爱…

浮点型在内存中的存储

目录 1.浮点数是什么&#xff1f; 2. 浮点数存储规则 1.浮点数是什么&#xff1f; 就是数学中的小数。 常见的浮点数&#xff1a; 3.14159 1E10&#xff08;1*10^10&#xff09; 浮点数家族包括&#xff1a; float、double、long double 类型。 浮点数表示的范围&#x…

Bean的生命周期

目录 1、实例化Bean 2、设置Bean的属性 3、初始化Bean &#xff08;1&#xff09;、执行通知 &#xff08;2&#xff09;、初始化的前置方法 &#xff08;3&#xff09;、初始化方法 &#xff08;4&#xff09;、执行自定义方法 &#xff08;5&#xff09;、初始化的后置…

API接口:如何通过使用手机归属地查询

随着手机普及率的不断增加&#xff0c;手机号码的信息查询也成为了一个非常实用的功能。本文将介绍如何通过使用手机归属地查询API接口实现查询手机号码所在地的功能。 首先&#xff0c;我们需要一个可以查询手机号码所在地的API接口。目前市面上有很多免费或付费的API接口可供…

《Ansible自动化工具篇:ubuntu操作系统基于ansible工具一键远程离线部署之K8S1.24.12二进制版集群》

一、部署背景 由于业务系统的特殊性&#xff0c;我们需要针对不同的客户环境部署二进制版K8S集群&#xff0c;由于大都数用户都是专网环境&#xff0c;无法使用外网&#xff0c;为了更便捷&#xff0c;高效的部署&#xff0c;针对业务系统的特性&#xff0c;我这边编写了 基于a…

uni-app中的uni.requireNativePlugin()

这个方法是用来引入原生插件的方法&#xff0c;自 HBuilderX 1.4 版本起&#xff0c;uni-app 支持引入原生插件&#xff0c;使用方式如下&#xff1a; const PluginName uni.requireNativePlugin(PluginName); // PluginName 为原生插件名称 引入插件的类型有三种&#xff1…

【idea工具】idea工具,build的时候提示:程序包 com.xxx.xx不存在的错误

idea工具&#xff0c;build的时候提示:程序包 com.xxx.xx不存在的错误&#xff0c;如下图&#xff0c;折腾了好一会&#xff0c; 做了如下操作还是不行&#xff0c;idea工具编译的时候&#xff0c;还是提示 程序包不存在。 a. idea中&#xff0c;重新导入项目&#xff0c;也还…

Mysql-主从复制与读写分离

Mysql 主从复制、读写分离 一、前言&#xff1a;二、主从复制原理1.MySQL的复制类型2. MySQL主从复制的工作过程;3.MySQL主从复制延迟4. MySQL 有几种同步方式&#xff1a;5.Mysql应用场景 三、主从复制实验1.主从服务器时间同步1.1 master服务器配置1.2 两台SLAVE服务器配置 2…

小程序自定义步骤条实现

效果展示&#xff1a; 支持背景颜色自定义 <view class"hl_steps"><view class"hl_steps_item" wx:for"{{steps}}" wx:key"id"><view class"hl_steps_item_circle_out" style"background-color: {{col…

【Linux网络】 网络套接字(三)socket编程_TCP网络程序

目录 TCP网络程序服务端创建套接字并绑定服务端监听服务端获取连接服务器处理请求 客户端客户端创建套接字客户端连接服务器客户端发起请求测试 服务器存在的问题多进程版的TCP网络程序多线程版的TCP网络程序线程池版的TCP网络程序 TCP网络程序总结图 TCP网络程序 服务端 创建…

踩坑_vertical-align

目录 问题&#xff1a;vertical-align属性语法父元素的基线怎么找呢&#xff1f;特殊元素的基线行盒 解决 问题&#xff1a; 今天在做一个需求时遇到了如下问题&#xff1a; 代码 <style>*{margin:0;padding:0;}#app{width: 300px;height: 117px;background: #FFFFFF;bo…

通过v-for生成的input无法连续输入

部分代码&#xff1a;通过v-for循环生成el-form-item&#xff0c;生成多个描述输入框 更改之前的代码&#xff08;key绑定的是item&#xff09;&#xff1a; <el-form-item class"forminput" v-for"(item,index) in formdata.description" :key"…

打造高效便捷的采购管理平台,提升企业采购效率

随着企业规模的扩大和供应链的日益复杂&#xff0c;传统的手工采购管理方式已经不能满足企业的需求。采购管理平台的出现为企业提供了一个集中、高效、便捷的采购管理工具。本文将重点探讨采购管理平台的意义与作用&#xff0c;并介绍如何打造一个高效便捷的采购管理平台。 一、…

PHY芯片的使用(三)在linux下网络PHY的移植

1 前言 配置设备树请参考上一章。此次说明还是以裕太的YT8511芯片为例。 2 需要配置的文件及路径 a. 在 .. /drivers/net/phy 目录下添加 yt_phy.c 文件&#xff08;一般来说该驱动文件由厂家提供&#xff09;&#xff1b; b. 修改.. /drivers/net/phy 目录下的 Kconfig 文…

欧盟新规,燃油噩梦?2025年起,高速公路每60公里设立一处快充站

根据外媒The Verge报道&#xff0c;欧洲电动汽车用户将获得更多便捷的待遇&#xff0c;同时还能减少有害温室气体排放&#xff0c;这得益于欧盟理事会最新通过的法规。 根据欧盟的法规要求&#xff0c;自2025年起&#xff0c;TEN-T高速公路系统在欧洲将需要每隔60公里设立一座高…