模拟实现链表的功能

1.什么是链表?

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。

 实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

  1. 单向或者双向                
  2. 带头或者不带头                      
  3. 循环或者非循环                                         

无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如 哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。  

无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。

2.如何定义一个链表?

无头单向链表的每一个节点有两个属性,分别是值val和存储下一个节点的地址。

我们来回顾内部类的定义:当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服 务,那么这个内部的完整结构最好使用内部类

这里我们把每个节点定义为内部类正合适

    static class ListNode {
        public int val;
        public ListNode next;

        public ListNode(int val) {

            this.val = val;
        }
    }
    public ListNode head;//定义头节点

此时的head: 

注:这里的next中存储的下一个节点的位置,所以类型是ListNode;

使用构造方法初始化的时候,仅仅初始化val的值,next节点默认为null

3.链表的模拟实现

这里我们模拟实现的是无头单向非循环链表 

// 1、无头单向非循环链表实现
 public class SingleLinkedList {
    //头插法
    public void addFirst(int data){
   }
    //尾插法
    public void addLast(int data){
   }
    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
   }
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        return false;
   }
    //删除第一次出现关键字为key的节点
    public void remove(int key){
   }
    //删除所有值为key的节点
    public void removeAllKey(int key){
   }
    //得到单链表的长度
    public int size(){
        return -1;
   }
 
    public void clear() {
   }
     
    public void display() {}
 }

 (1)头插addFirst的实现

解析:

假设有这样一组链表,我们想把node节点添加到该链表的头节点

实现效果:

  1. 创建需要头插的node节点
  2. 我们需要把node节点的next指向下一个结点的地址
  3. 把node节点变为头节点即可
public void addFirst(int val) {
        ListNode node = new ListNode(val);
        node.next = head;
        head = node;
    }

(2)尾插addLast的实现

解析: 

实现效果:

思路:

  1. 创建需要尾插的node节点
  2. 通过循环找到链表的最后一个节点,将原本链表最后节点的next的null变为所要尾插节点的地址

操作:

  1. 空链表怎么处理?
    首先我们判断链表是否是空链表,如果是,直接将node节点变为头节点即可
  2. 怎么找到链表的最后一个节点?
    通过while循环遍历来找到链表的最后一个节点,如果没找到就一直循环移动到下一个节点,如果找到了,我们将node的地址赋值给最后一个节点的next
  3. 为什么要定义cur节点来遍历?
    我们定义一个cur节点来存储head节点,以防遍历后数据丢失
  4. 循环的条件?
    while循环的条件,判断每个节点的next是否为空,为空说明找到了最后一个节点,也就是cur.next != null
public void addLast(int val) {
        ListNode cur = head;
        ListNode node = new ListNode(val);
        if(head == null) {
            head = node;
            return;
        }
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = node;
    }

 (3)addIndex()的实现

此方法实现在任意位置插入节点 

实现效果:
思路:

  1. 找到所要插入位置的前一个节点
  2. 将node的next指向cur的next节点;将前一个结点cur的next指向node的地址

操作:

  1. 如何处理传入的下标不合法问题?
    这里我们定义一个异常处理,当下标小于0,或者大于链表长度时,抛出异常,并用try  catch()语句来进行异常的捕获
  2. 插入的位置在头部和尾部怎么处理?
    对应头插法和尾插法,直接调用写好的方法即可
  3. 如何找到前一个结点?
    我们可以专门写一个方法来实现此操作,定义一个count变量来表示循环次数,只需循环到index-1的位置即可
  4. 如何进行连接?
    将node的next指向cur的next节点;将前一个结点cur的next指向node的地址。需要注意的是需要先将添加的节点与后面的节点进行绑定,再对前面的进行绑定
public void addIndex(int index, int val) {
        //1.判断合法性
        try {
            checkIndex(index);
        }catch (IndexNotLegalException e) {
            e.printStackTrace();
        }
        //2.index == 0  || index == size()
        if(index == 0) {
            addFirst(val);
            return;
        }
        if(index == size()) {
            addLast(val);
            return;
        }
        //找到前一个结点
        ListNode cur = findIndexSubOne(index);
        //4. 进行连接
        ListNode node = new ListNode(val);
        node.next = cur.next;
        cur.next = node;
    }
    private ListNode findIndexSubOne(int index) {
        ListNode cur = head;
        int count = 0;
        while (count != index-1) {
            cur = cur.next;
            count++;
        }
        return cur;
    }
    private void checkIndex(int index) throws IndexNotLegalException{
        if(index < 0 || index > size()) {
            throw new IndexNotLegalException("index不合法");
        }
    }

IndexNotLegalException.java 文件

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

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

(4)contains()的实现

此方法判断链表中是否包含val值,包含则返回true,否则返回false

思路:

  1. 遍历链表,与每个节点的val值进行对比

操作:

  1. 循环的条件?
    因为需要将每个节点的val值进行比较,所以条件为cur != null;
  2. 如果找到就返回true,如果没有就继续遍历,遍历完好没找到就返回false;
    public boolean contains(int val) {
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == val) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

(5)remove()的实现

此方法是删除第一次出现关键字为val的节点

实现效果:

思路:

  1. 找到所要删除节点的前一个节点,将该节点与所要删除节点的后一个节点进行拼接来完成删除操作

操作:

  1. 如何找到所要删除节点的前一个节点?
    当cur.next.val == 34(所要删除的节点)时,定义一个del节点,cur的下一个节点就是del,ListNode del = cur.next;
    为什么不能用cur.val而用cur.next.val来对比判断所要删除的节点呢?
    因为此时是一个单向的链表当我们的cur走到要删除的节点是就不能修改前面的节点了,这样就无法实现改变前一个结点的val值了
  2. 如何进行删除?
    我们定义所要删除的节点为del,将cur的next指向del的next,即:cur.next = del.next;(cur.next = cur.next.next)
  3. 循环条件是什么?
    判断每个节点的val是否是所要删除的val,循环条件是cur.next != null,通过cur.next.val就可以访问到下一个节点的val值。
    为什么不能通过cur != null来作为循环条件呢?
    在我们寻找删除结点的前一个节点时,我们是通过cur.next.val == 34(所要删除的节点)进行值的对比来寻找,如果我们通过cur != null来判断,当cur走到最后一个节点时,next为null,此时cur.next.val就会出现空指针异常
  4. 为什么需要特殊判断头节点?
    因为我们是通过cur.next.val来开始判断的,并没有判断头节点的val值
    所以我们需要进行特殊判断, head = head.next;
public void remove(int val) {
        if(head == null) {
            return;
        }
        if(head.val == val) {
            head = head.next;
            return;
        }
        ListNode cur = head;
        while (cur.next != null) {
            if (cur.next.val == val) {
                ListNode del = cur.next;
                cur.next = del.next;
                return;
            }
            cur = cur.next;
        }
    }

(6)removeAllKey()的实现

此方法是删除所有出现关键字为val的节点

操作:

  1. cur代表当前需要删除的节点

    prev代表当前需要删除节点cur的前驱节点

  2. 如果找到需要删除的节点,prev.next = cur.next;cur = cur.next;

  3. 如果没找到所要删除的节点,移动prev节点prev = cur;再移动cur判断下一个节点cur = cur.next;

  4. 最后的效果

  5. 如何处理头节点就是要删除的节点的情况?

    先将头节点以外的删除再来考虑头节点位置即可
    if(head.val == val) {
                head = head.next;
            }

    也可先考虑头节点的情况,while循环判断

public void removeAllKey(int val) {
        //1. 判空
        if (head == null) {
            head = head.next;
        }
        //2. 定义prev 和 cur
        ListNode prev = head;
        ListNode cur = head.next;
        //3.开始判断并且删除
        while (cur != null) {
            if (cur.val == val) {
                //找到了
                prev.next = cur.next;
            } else {
                prev = cur;
            }
            cur = cur.next;
        }
        //4.处理头节点
        if(head.val == val) {
            head = head.next;
        }
    }

(7)size()的实现

遍历链表,用count计数即可

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

(8)clear()的实现

将每一个节点的next置空即可,注意这里需要单独把头节点置空

public void clear() {
        ListNode cur = head;
        while (cur != null) {
            ListNode curN = cur.next;
            //cur.val = null;
            cur.next = null;
            cur = curN;
        }
        head = null;
    }

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

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

相关文章

猫头虎分享已解决Bug || Node.js安装失败Error: unable to connect to https://nodejs.org/猫头虎

猫头虎分享已解决Bug || Node.js安装失败Error: unable to connect to https://nodejs.org/猫头虎 博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — …

活动回顾 |观测云 AI Agent 探索实践

亚马逊云科技“构建全球化软件和互联网新生态——ISV 行业”论坛上&#xff0c;观测云产品架构师刘锐发表了题为“AI Agent 可观测性探索与实践”的主题演讲&#xff0c;不仅展示了观测云在人工智能领域的前沿技术&#xff0c;更强调了在日益复杂的系统环境中&#xff0c;实现有…

autoware.universe 使用之Rosbag replay simulation放包仿真

本文将按照官方文档&#xff0c;通过播放rosbag录制包进行可视化模拟&#xff0c;中间也报了很多错误&#xff0c;特此记录下来&#xff0c;以免后续踩坑。 电脑配置如下&#xff1a;    ubuntu20.04    cuda: cuda-11.6    nvidia-driver 535    ros2: foxy 关于auto…

「MDN web 入门」学习笔记

目录 写在前面 1. MDN 简介 1.1 MDN 的主要特点 1.2 MDN 的主要功能 1.3 MDN 网页开发的指南 2. 安装基础软件 2.1 专业人士工具 2.2 初学者基本工具 3. 设计网站外观 3.1 计划 3.2 绘制草图 3.3 选定素材 3.4 文本 3.5 主题颜色 3.6 图像 3.7 字体 4. 处理文…

Redis(无中心化集群搭建)

文章目录 1.无中心化集群1.基本介绍2.集群说明 2.基本环境搭建1.部署规划&#xff08;6台服务器&#xff09;2.首先删除上次的rdb和aof文件&#xff08;对之前的三台服务器都操作&#xff09;1.首先分别登录命令行&#xff0c;关闭redis2.清除/root/下的rdb和aof文件3.把上次的…

认识卷积神经网络

我们现在开始了解卷积神经网络&#xff0c;卷积神经网络是深度学习在计算机视觉领域的突破性成果&#xff0c;在计算机视觉领域&#xff0c;往往我们输入的图像都很大&#xff0c;使用全连接网络的话&#xff0c;计算的代价较高&#xff0c;图像也很难保留原有的特征&#xff0…

oracle 数据库找到UDUMP的文件名称

oracle 数据库找到UDUMP的文件名称 select p.value||\||i.instance_name||_ora_||spid||.trc as "trace_file_name" from v$parameter p ,v$process pro, v$session s, (select sid from v$mystat where rownum1) m, v$instance i where lower(p.name)user_dump_…

Java_File

介绍&#xff1a; File对象表示路径&#xff0c;可以是文件&#xff0c;也可以是文件夹。这个路径可以是存在的&#xff0c;也可以是不存在的&#xff0c;带盘符的路径是绝对路径&#xff0c;不带盘符的路径是相对路径&#xff0c;相对路径默认到当前项目下去找 构造方法&…

英伟达推出视觉语言模型:VILA

NVIDIA和MIT的研究人员推出了一种新的视觉语言模型(VLM)预训练框架&#xff0c;名为VILA。这个框架旨在通过有效的嵌入对齐和动态神经网络架构&#xff0c;改进语言模型的视觉和文本的学习能力。VILA通过在大规模数据集如Coy0-700m上进行预训练&#xff0c;采用基于LLaVA模型的…

三.Django--ORM(操作数据库)

目录 1 什么是ORM 1.1 ORM优势 1.2ORM 劣势 1.3 ORM与数据库的关系 2 ORM 2.1 作用 2.2 连接数据库 2.3 表操作--设置字段 2.4 数据库的迁移 写路由增删改查操作 项目里的urls.py: app里的views.py: 注意点: 1 什么是ORM ORM中文---对象-关系映射 在MTV,MVC设计…

2024面试自动化测试面试题【含答案】

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

若依框架dialog弹窗取消点击空白出关闭

如果想全局取消的话就找到main.js在里面加上下面的一行代码&#xff0c;添加完成之后记得清楚浏览器缓存重新加载js文件。 Element.Dialog.props.closeOnClickModal.default false;如果想指定某个弹窗取消点击空白处关闭&#xff0c;那么就找到那个弹窗加上。添加完毕之后刷新…

扩散模型~

推荐&#xff1a;write_own_pipeline.ipynb - Colab (google.com) 基本管道 一直显示NVIDIA有问题&#xff0c;所以就把.to("cuda")去掉了&#xff0c;使用Colab运行的&#xff0c;代码如下&#xff1a; from diffusers import DDPMPipelineddpm DDPMPipeline.fr…

哈希题目总结

以下列举了可以用哈希方法&#xff08;包括但不限于用HashMap和HashSet&#xff09;的题目&#xff0c;实质上是把东西丢给这些数据结构去维护。请注意有些题目中用哈希是最优解&#xff0c;有些题目中不是最优解&#xff0c;可以自行探索其时间复杂度和空间复杂度的区别&#…

java入门1.1.1版本

前言&#xff1a; 上面的内容是1.0.0~1.1的内容总结 秉持着先做再定义的理念&#xff0c;这里会带着大家先体验一下类与对象 第一步&#xff1a;新建一个java文件 鼠标右键 → 新建 → 文本文档 → 右键 → 点击重名 → 全选 → hello.java 第二步&#xff1a;用笔记本打开 …

阿里云开发uniapp之uni-starter

一、为什么使用uni-starter uni-starter是集成商用项目常见功能的、云端一体应用快速开发项目模版。 一个应用有很多通用的功能&#xff0c;比如登录注册、个人中心、设置、权限管理、拦截器、banner... uni-starter将这些功能都已经集成好&#xff0c;另外&#xff0c;uni-s…

2023-2024年SaaS行业报告合集(精选22份)

SaaS行业报告/方案&#xff08;精选21份&#xff09; 2023-2024年 报告来源&#xff1a;2023-2024年SaaS行业报告合集&#xff08;精选22份&#xff09; 【以下是资料目录】 2024中国HCM SaaS领导者竞争力持续增强的行业龙头 2024年中国企业级SaaS行业研究报告 2024年SaaS…

基于Transformer网络的多步预测模型

包括完整流程数据代码处理&#xff1a; 多步预测数据集制作、数据加载、模型定义、参数设置、模型训练、模型测试、预测可视化、多步预测、模型评估 ● 环境框架&#xff1a;python 3.9 pytorch 1.8 及其以上版本均可运行 ● 使用对象&#xff1a;论文需求、毕业设计需求者…

Offer必备算法37_记忆化搜索_五道力扣题详解(由易到难)

目录 记忆化搜索概念和使用场景 ①力扣509. 斐波那契数 解析代码1_循环 解析代码2_暴搜递归 解析代码3_记忆化搜索 解析代码4_动态规划 ②力扣62. 不同路径 解析代码1_暴搜递归&#xff08;超时&#xff09; 解析代码2_记忆化搜索 解析代码3_动态规划 ③力扣300. 最…

最详尽的网络安全学习路线!涵盖所有技能点,带你成为网安专家!

目录 零基础小白&#xff0c;到就业&#xff01;入门到入土的网安学习路线&#xff01; 建议的学习顺序&#xff1a; 一、夯实一下基础&#xff0c;梳理和复习 二、HTML与JAVASCRIPT&#xff08;了解一下语法即可&#xff0c;要求不高&#xff09; 三、PHP入门 四、MYSQL…
最新文章