单链表——你需要掌握的那些内容

news2024/11/23 15:16:52

如有错误,感谢不吝赐教、交流

文章目录

  • 前言
  • 本文涉及题目:设计链表
  • 有无头结点的区别
    • 头指针
    • 无头结点
    • 有头结点
    • 为什么需要头结点呢?
    • 注意:
  • 单链表,本文使用Java实现
    • 定义链表节点
    • 定义一个链表类并初始化
    • get(int index)
    • addAtHead(int val)
    • addAtTail(int val)
    • addAtIndex(int index, int val)
    • deleteAtIndex(int index)
  • 完整Java代码

前言

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成;
(数据域,指针域(存放下一个节点的指针));
最后一个节点的指针指向null;
如图示例:
在这里插入图片描述

本文涉及题目:设计链表

leetcode707

有无头结点的区别

头指针

不管是有头结点或者是没有头结点,头指针都是指向链表的第一个节点,具体区别,看下面;

无头结点

在这里插入图片描述
对于没有头结点的链表,头指针指向的就是链表的第一个存储数值的节点。即head就是链表的第一个节点。

有头结点

在这里插入图片描述
对于有头结点的链表,头指针指向的是头结点,头结点的下一个节点是第一个存储数值的节点。即head.next才是链表的第一个节点。

为什么需要头结点呢?

对于没有头结点的链表,在操作第一个节点和剩余节点会出现不同的情况。
对于链表如图所示的不带头结点的链表,要插入一个新的节点:
原始不带头结点的链表:
在这里插入图片描述
在第一个节点之前插入新节点,需要修改head指针指向新的节点:
在这里插入图片描述
在不是第一个节点之前插入新节点,不需要修改head指针:
在这里插入图片描述
两种插入方式是不同的;

下面我们看看带头结点的链表插入新节点:
在这里插入图片描述
注意看第一个节点之前插入和剩余节点之前插入,两种情况是一样,相比不带头结点的链表,更加方便。

注意:

在实现或者做题的时候,一定要弄清楚head指向的是不是头结点,两种情况的答案完全不同。

单链表,本文使用Java实现

如上面所示的就是单链表,接下来我们看看单链表怎么去实现和使用。

定义链表节点

class ListNode {
    int val;  // 数值域
    ListNode next;  // 指针域
    public ListNode() {}
    public ListNode(int val) {
        this.val = val;
    }
}

定义一个链表类并初始化

MyLinkedList() 初始化 MyLinkedList 对象

class MyLinkedList {
    // 记录有多少个节点
    int size;
    // 头结点
    ListNode head;

    public MyLinkedList() {
        // 初始化链表
        size = 0;
        head = new ListNode(0);
    }
}

get(int index)

int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1
直接遍历即可返回对应位置节点的值。

public int get(int index) {
        // 索引违规
        if (index < 0 || index >= size) {
            return -1;
        }
        ListNode p = head;  // 遍历指针
        while (index > 0) {
            p = p.next;
            index--;
        }
        return p.next.val;
    }

addAtHead(int val)

void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
可以参见上面的图中在头结点之后插入节点。

public void addAtHead(int val) {
        ListNode newNode = new ListNode(val);
        newNode.next = head.next;
        head.next = newNode;
        size++;
    }

addAtTail(int val)

void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
遍历到最后一个节点,直接插入。

public void addAtTail(int val) {
        ListNode p = head;
        // 找到尾指针
        while(p.next != null) {
            p = p.next;
        }
        ListNode newNode = new ListNode(val);
        newNode.next = null;
        p.next = newNode;
        size++;
    }

addAtIndex(int index, int val)

void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
在这里插入图片描述

public void addAtIndex(int index, int val) {
        // 违规索引
        if (index < 0 || index > size) {
            return;
        }
        ListNode newNode = new ListNode(val);

        ListNode p = head;
        if (index == 0) {
            // 在头结点之后插入
            newNode.next = head.next;
            head.next = newNode;
            size++;
        } else {
            while(index > 0) {
                p = p.next;
                index--;
            }
            newNode.next = p.next;
            p.next = newNode;
            size++;
        }
    }

deleteAtIndex(int index)

void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。
找到对应的索引位置,如图所示删除。
在这里插入图片描述

public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        ListNode p = head;
        if (index == 0) {
            head = head.next;
            size--;
            return;  // 这里删除之后就不执行后面的操作了
        }
        while(index > 0) {
            p = p.next;
            index--;
        }
        p.next = p.next.next;
        size--;
    }

完整Java代码

class MyLinkedList {
    // 记录有多少个节点
    int size;
    // 头结点
    ListNode head;

    public MyLinkedList() {
        // 初始化链表
        size = 0;
        head = new ListNode(0);
    }
    
    public int get(int index) {
        // 索引违规
        if (index < 0 || index >= size) {
            return -1;
        }
        ListNode p = head;  // 遍历指针
        while (index > 0) {
            p = p.next;
            index--;
        }
        return p.next.val;
    }
    
    public void addAtHead(int val) {
        ListNode newNode = new ListNode(val);
        newNode.next = head.next;
        head.next = newNode;
        size++;
    }
    
    public void addAtTail(int val) {
        ListNode p = head;
        // 找到尾指针
        while(p.next != null) {
            p = p.next;
        }
        ListNode newNode = new ListNode(val);
        newNode.next = null;
        p.next = newNode;
        size++;
    }
    
    public void addAtIndex(int index, int val) {
        // 违规索引
        if (index < 0 || index > size) {
            return;
        }
        ListNode newNode = new ListNode(val);

        ListNode p = head;
        if (index == 0) {
            // 在头结点之后插入
            newNode.next = head.next;
            head.next = newNode;
            size++;
        } else {
            while(index > 0) {
                p = p.next;
                index--;
            }
            newNode.next = p.next;
            p.next = newNode;
            size++;
        }
    }
    
    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        ListNode p = head;
        if (index == 0) {
            head = head.next;
            size--;
            return;  // 这里删除之后就不执行后面的操作了
        }
        while(index > 0) {
            p = p.next;
            index--;
        }
        p.next = p.next.next;
        size--;
    }
}

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

ps:计划每日更新一篇博客,今日2023-04-27,日更第十一天。
昨日更新:
如何求解递归式的时间复杂度

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

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

相关文章

HAproxy与web集群

文章目录 一、HAproxy1.HAProxy是什么2.HAProxy的核心能力和关键特性3.LVS、Nginx、HAproxy的区别&#xff1a; 二、实验步骤1.Haproxy搭建 Web 群集 总结 一、HAproxy 1.HAProxy是什么 HAProxy是一个免费的负载均衡软件&#xff0c;可以运行于大部分主流的Linux操作系统上。…

儿童生长发育迟缓的鉴别和干预

&#xff08;英国&#xff09;国家临床医学研究所&#xff08;NICE&#xff09;2017年发布关于婴儿/儿童生长发育迟缓的鉴别、评估和监测的指南&#xff0c;该指南确定了生长发育的界值&#xff0c;指出了诱因及危险因素&#xff0c;并提出了干预的方案。 ▼Part1&#xff1a;…

“无人值守”时代已来,千巡翼X4给出怎样的答案?

随着技术和产品的逐渐成熟&#xff0c;无人机在各行业的应用越来越普遍&#xff0c;但如何进一步解放人力&#xff0c;提高运营效率&#xff0c;还有很大的探索空间。针对作业频率高、重复性高、周期性强、作业环境艰险危险等痛点&#xff0c;用户迫切需要更高效、更智能的全自…

LeetCode876. 链表的中间结点

876. 链表的中间结点 描述示例解题思路以及代码解法1解法2 描述 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例 示例1 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[3,4,5] 解释…

希尔排序的实现

希尔排序是插入排序的一种升级&#xff0c;其基本思想是&#xff1a; 先选定一个整数&#xff0c;把待排序文件中所有记录分成个组&#xff0c;所有距离为的记录分在同一组内&#xff0c;并对每 一组内的记录进行排序。然后&#xff0c;取&#xff0c;重复上述分组和排序的工 作…

可执行Jar项目

一个复杂Jar的运行&#xff0c;要解决classpath问题&#xff0c;否则运行时会有ClassNotFoundException抛出。而用java&#xff0c;需要手动维护一个classpath文件&#xff0c;或者将所有的库位置放到命令行参数里。有没有更好的办法&#xff1f; Jar库目录方式 核心配置在于两…

算法训练Day40:343. 整数拆分 96.不同的二叉搜索树

文章目录 整数拆分题解&#xff08;动态规划&#xff09;贪心 不同的二叉搜索树题解 整数拆分 CategoryDifficultyLikesDislikesContestSlugProblemIndexScorealgorithmsMedium (62.22%)11660--0 Tags 数学 | 动态规划 Companies 给定一个正整数 n &#xff0c;将其拆分为…

推荐几个免费的在线文本转语音网站(支持中英文多种语音)

如果你正在寻找一款免费的在线文本转语音工具&#xff0c;那么你来对地方了&#xff01;本文将介绍几个完全免费的在线文本转语音网站&#xff0c;推荐收藏下来以备不时之需。 No.1 免费文本转语音&#xff08;TTSMaker&#xff09; TTSMaker是第一个推荐的工具&#xff0c;这…

院内导航方案怎么样?什么地图可以用于医院导航系统?

什么地图可以用于医院导航系统&#xff1f;随着医疗事业的不断发展&#xff0c;医院的建制规模越来越大&#xff0c;在医疗能力得到增强的同时&#xff0c;由于楼宇众多&#xff0c;院内寻路难度难免增加。不少前来医院就诊的患者经常会有“寻路难”的困扰。此时一张一目了然的…

从在线监测与故障诊断系统视角,探讨动设备安全运行的重要性

在工业生产中&#xff0c;动设备是生产线的重要组成部分&#xff0c;但是随着设备运行时间的不断延长&#xff0c;设备的损耗逐渐加大&#xff0c;设备故障和损坏的风险也随之增加&#xff0c;给生产效率和安全带来不小的影响。因此&#xff0c;如何保证动设备的安全运行成为了…

更简单的存取Bean的方式(一)-五大类注解

目录 使用类注解 前置工作 Bean命名规则 五大类的实现 JavaEE标准分层 之前我们存储Bean时,是在spring-config.xml文件中添加bean注册内容来实现的 通过"注解"我们可以替代这一项工作 更加简单的存储方式: 使用类注解 五大类注解: Controller(控制器):用来控制…

常用的倾斜摄影三维模型3DTILES格式优缺点分析

常用的倾斜摄影三维模型3DTILES格式优缺点分析 三维模型3DTILES格式是一种用于描述三维模型和场景数据的标准格式&#xff0c;具有以下优点和缺点&#xff1a; 优点&#xff1a; 1、多平台支持&#xff1a;3DTILES格式基于WebGL和JavaScript技术&#xff0c;可以在多个平台上…

用Python搞定接口自动化测试:轻松实现RPC协议接口测试

每天进步一点点&#xff0c;关注我哦&#xff0c;每天分享测试技术文章&#xff0c;文末有福利&#xff01; 目录&#xff1a;导读 前言 一、什么是RPC 二、RPC框架 三、基于grpc框架服务的接口测试 01创建一个grpc服务接口 02调用grpc接口客户端 03接口框架中适配grpc封…

nvm安装使用详解,附gnvm介绍

最近工作中&#xff0c;再次遇到了需要处理 Node.js 多版本管理的事情&#xff0c;由于在windows系统下开发&#xff0c;于是使用了 nvm 来做版本管理。 其实&#xff0c;之前在写文章介绍 进行node和npm的版本升级 的时候&#xff0c;也有提到 node 多版本管理工具&#xff0c…

史上最全Maven教程(五)

文章目录 &#x1f525;Maven聚合案例_搭建dao模块&#x1f525;Maven聚合案例_搭建service模块&#x1f525;Maven聚合案例_搭建web模块&#x1f525;Maven聚合案例_运行项目&#x1f525;依赖传递失效及解决方案 &#x1f525;Maven聚合案例_搭建dao模块 dao子工程中一般写实…

linux交叉编译环境搭建 gcc + openocd + stlink + cubeMX + cortex Debug

文章目录 运行环境&#xff1a;1.1 gcc1)下载并解压gcc2)环境配置 2.1 openocd1)下载并解压openocd2)环境配置&#xff08;没有权限就加sudo&#xff09; 3.1 stlink1)下载并双击安装stlink 4.1 cubeMX1)下载并解压cubeMX2)生成makefile工程 5.1 cortex Debug1)setting设置2)la…

国家信息安全水平考试中NISP二级网络安全证书介绍

国家信息安全水平考试中NISP二级网络安全证书介绍 1、什么是NISP? 国家信息安全水平考试&#xff08;National Information Security Test Program&#xff0c;简称NISP&#xff09;&#xff0c;是由中国信息安全测评中心实施培养国家网络空间安全人才的项目。 2、考取NISP…

电信运营商网络运维方案

随着新一代信息技术加快普及应用&#xff0c;5G、云和人工智能正加速智能社会的到来&#xff0c;三大技术正在重构网络。随着我国5G产业快速推进&#xff0c;中国移动、中国联通、中国电信加快步伐&#xff0c;全业务运营时代已经到来。全业务运营时代的特点是&#xff1a;网络…

ros2 foxy创建一个包和节点-ubuntu20.04

文章目录 创建工作区目录创建包和节点colcon build编译CMakeLists.txt文件find_packageadd_executable package.xml面相过程的方式生命一个节点以面向对象的方式创建一个节点 创建工作区目录 mkdir -p ~/ros2_ws/src cd ~/ros2_ws我们创建了两个目录&#xff0c;ros2_ws和在他…

echarts实用经验:tooltip悬浮框添加button按钮;toolbox添加自定义按钮;显示隐藏切换导致图表太小渲染不及时的解决办法

一、tooltip悬浮框添加点击事件 这里我配置的是在柱状图中&#xff0c;echarts配置项文档 注意&#xff1a; 1、tooltip&#xff0c;默认是鼠标移动时触发&#xff08;‘mousemove’&#xff09;。这种情况下&#xff0c;是无法点击到悬浮框的&#xff0c;更别说点击框内的按钮…