LInkedList的模拟实现

news2024/11/29 20:35:13

在之前的文章笔者介绍了链表的实现:无头单向非循环链表的实现!感兴趣的各位老铁可以点进来看看:https://blog.csdn.net/weixin_64308540/article/details/128397961?spm=1001.2014.3001.5502

对于此篇博客,在一写出来,便引起了巨大反响!!那么后续来了!!今日,笔者来带领大家走进:LinkedList的模拟实现!(底层是双向链表结构)

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

我们来看一下实现的主要代码:

总体的方法:

public class MyLinkdeList {
    //无头双向链表的实现
    
    //头插法
    public void addFrist(int data){
    }
    
    //尾插法
    public void addLast(int data){
    }
    
    //任意位置插入,第一个数据节点的下标为0
    public void addIndex(int index,int data){
    }
    
    //查找关键字key是否在链表当中
    public boolean contains(int key){
    }
    
    //删除第一次出现关键字为key的节点
    public void remove(int key){
    }
    
    //删除所有值为key的节点
    public void removeAllkey(int key){
    }
    
    //得到链表的长度
    public int size(){
    }
    
    public void display(){
    }
    
    public void clear(){
    }
}

那么接下来就跟着笔者的思路,来实现这些方法吧!!

实现该方法之前的准备!每个节点所必须的东西!!

   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;//永远指向链表的最后一个节点

经过上述的准备,那么我们就可以安心实现上述的方法了!!

下面笔者便以下图的链表进行讲解:

    • 打印链表:
    //打印链表
    public void display(){
        ListNode cur=head;
        while (cur !=null){
            System.out.print(cur.val+" ");
            cur=cur.next;
        }
        System.out.println();
    }

很简单的一个代码,想必没有什么需要讲解的吧!!

2.得到链表的长度
    //得到链表的长度
    public int size(){
        int len=0;
        ListNode cur=head;
        while (cur != null){
            len++;
            cur=cur.next;
        }
        return len;
    }

这个就是在遍历链表的过程中,定义了一个len,每次进行++,从而得到链表的长度!

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

这个思路很简单,遍历一遍链表,当有val的值等于key的时候,直接return true即可!!如果链表遍历完毕,没有值等于key那么最后return false就行了!

4.头插法

时间复杂度为O(1)

头插法,顾名思义就是插到头节点之前呗!!

    //头插法
    public void addFrist(int data){
        //实列化一个新的节点
        ListNode node =new ListNode(data);
        if (head==null){
            head=node;
            last=node;
        }else {//先绑后面
            node.next=head;
            head.prev=node;
            head=node;//新的头节点
        }
    }

上述代码,我们可以从图中得出大致思路

5.尾插法

时间复杂度为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;
        }
    }

其实尾插法跟头插法的情况差不多!!很类似!!

6。任意位置插入,第一个数据节点的下标为0

对于想要插入数据的下标,我们首先需要判断其合法性!!然后在判断是否为头插法或者尾插法!!最后在考虑在链表内部的插入!!由于该链表是双向的链表,那么,我们可以找到index位置所对应的节点!

 //任意位置插入,第一个数据节点的下标为0
    public void addIndex(int index,int data){
        if(index <0 || index >size()){
            System.out.println("输入的位置不合法,请重新确定想要插入的位置!");
        }
        if (index==0){//头插法
            addFrist(data);
        }
        if (index==size()){//尾插法
            addLast(data);
        }
        //此时的index就是真正需要插入的地方了!
        //找到index位置的下标
        ListNode cur=findIndex(index);

        //实列化index位置处的data节点
        ListNode node=new ListNode(data);
        //开始插入
        node.next=cur;
        cur.prev.next=node;
        node.prev=cur.prev;
        cur.prev=node;
    }

    //找到index位置的下标
    public ListNode findIndex(int index){
        ListNode cur=head;
        while (index !=0){
            index--;
            cur=cur.next;
        }
        return cur;
    }

这个列子涉及很多分析地方!!所以需要珍惜一下!好好画图分析

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

对于该案列,我们需要找到想要删除的节点!若是头节点,我们应该怎么办??若是中间或者最后的节点,我们,又应该怎么办??这些都需要我们去认真思考!

 //删除第一次出现关键字为key的节点
    public void remove(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 {
                    //中间  尾巴节点
                    cur.prev.next=cur.next;
                    //不是尾巴节点
                    if (cur.next !=null){
                        cur.next.prev=cur.prev;
                    }else {
                        //是尾巴节点
                        last=last.prev;
                    }
                }
            }
            return;
        }
        cur=cur.next;
    }

希望大家能够理性的分析!!

8.删除所有值为key的节点

对于这个案列,我们可以经过上面的简单改变一下就可以了!!

  //删除所有值为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 {
                    //中间  尾巴节点
                    cur.prev.next=cur.next;
                    //不是尾巴节点
                    if (cur.next !=null){
                        cur.next.prev=cur.prev;
                    }else {
                        //是尾巴节点
                        last=last.prev;
                    }
                }
            }
        }
        cur=cur.next;
    }
9.清除所有节点

第一开始笔者的想法也是,直接:head==null, last==null但是,感觉这样写虽然是这个道理,却总感觉有点儿不得劲,所以最后决定,遍历一遍链表,将每个节点的prev与last全部都置为null!!

  //清除所有节点
    public void clear(){
        while (head !=null){
            head.prev=null;
            head.next=null;
            head=head.next;
        }
        head=null;
        last=null;
    }

经过上面的全部代码,笔者可算是将:LinkedList的模拟实现!(底层是双向链表结构)给整理完毕了!!不容易,下面请看笔者所整理的全部代码吧!!

public class MyLinkdeList {
    //无头双向链表的实现

    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;//永远指向链表的最后一个节点

    //头插法
    public void addFrist(int data){
        //实列化一个新的节点
        ListNode node =new ListNode(data);
        if (head==null){
            head=node;
            last=node;
        }else {//先绑后面
            node.next=head;
            head.prev=node;
            head=node;//新的头节点
        }
    }

    //尾插法
    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()){
            System.out.println("输入的位置不合法,请重新确定想要插入的位置!");
        }
        if (index==0){//头插法
            addFrist(data);
        }
        if (index==size()){//尾插法
            addLast(data);
        }
        //此时的index就是真正需要插入的地方了!
        //找到index位置的下标
        ListNode cur=findIndex(index);

        //实列化index位置处的data节点
        ListNode node=new ListNode(data);
        //开始插入
        node.next=cur;
        cur.prev.next=node;
        node.prev=cur.prev;
        cur.prev=node;
    }

    //找到index位置的下标
    public ListNode findIndex(int index){
        ListNode cur=head;
        while (index !=0){
            index--;
            cur=cur.next;
        }
        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){
                //删除的是头节点
                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){
                //删除的是头节点
                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(){
        while (head !=null){
            head.prev=null;
            head.next=null;
            head=head.next;
        }
        head=null;
        last=null;
    }
}

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

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

相关文章

java学习day72(乐友商城)微信支付实现

今日目标&#xff1a; 会调用订单系统接口 实现订单结算功能 实现微信支付功能 1.订单系统接口 我们不做开发&#xff0c;只讲解 1.1.导入订单服务 把课前资料提供的leyou-order复制到D:\heima\code\leyou目录。 然后在工程内导入&#xff1a; 然后导入module&#xff1a…

java:责任链设计模式配合Spring@Order注解使用场景

java&#xff1a;责任链设计模式配合SpringOrder注解使用场景 1 前言 java的责任链模式&#xff0c;经典使用的场景为SpringMVC的doDispatch下&#xff0c;针对请求的过滤链式行为。实际开发场景中&#xff0c;可配合Spring的Order注解&#xff0c;定义1个有顺序的链式Compon…

我在深圳的三次工厂旅程 (一)

2019年末加入一家人工智能AI创业公司&#xff0c;由于公司涉及到智能硬件产品&#xff0c;所以有机会参与到硬件产品的整个研发测试端、产品迭代流、工厂生产序等方面的这些事情。相对于研发测试、产品迭代这些在过往的工作中经历中相对比较熟悉和接触频繁&#xff0c;在软件产…

鉴定完毕!来看看跨年晚会谁假唱了…欧莱雅智能画眉设备;首个AI律师下月出庭;推特又裁员;GitHub今日热榜 | ShowMeAI资讯日报

&#x1f440;日报合辑 | &#x1f3a1;AI应用与工具大全 | &#x1f514;公众号资料下载 | &#x1f369;韩信子 &#x1f3a1; 『谁在假唱』技术手段分析跨年演唱会上的歌手们 各大卫视的跨年演唱会&#xff0c;你追了几场&#xff1f;看出来了谁在对口型&#xff1f;B站Up主…

【北京理工大学-Python 数据分析-2.2Matplotlib绘制饼图、直方图、极坐标、散点图】

pyplot的基础图标函数 函数说明plt.plot(x,y,fmt,…)绘制一个坐标图plt.boxplot(data,notch,position)绘制一个箱型图plt.bar(left,height,width,bottom)绘制一个条形图plt.barh(width,bottom,left,height)绘制一个横向条形图plt.polar(theta,r)绘制极坐标图plt.psd(x,NFFT256…

Dokcer14_5:Docker Compose volumes解析、Docker Compose volumes目录路径生成规则

Dokcer14_5&#xff1a;Docker Compose volumes解析、Docker Compose volumes目录路径生成规则docker-compose volumes语法语法格式及其三种变体1.无来源 &#xff1a;匿名挂载主机系统上的目录路径2.非路径源&#xff1a;具名挂载&#xff08;常用&#xff09;主机系统上的目录…

mysql idb,frm文件复制恢复

idb是innodb数据文件frm是innodb表结构文件在数据库的data目录下可以看到 data下的目录名就是数据库名&#xff0c;打开该数据库文件夹对于一个表有2个文件&#xff0c;一个以idb结尾&#xff0c;一个以frm结尾直接复制粘贴是不识别的&#xff0c;提示找不到该表解决方法&#…

在线实习项目|Python爬虫助力疫情数据追踪在线实习项目

项目介绍 项目背景&#xff1a;2019-NCOV新型冠状病毒引发的肺炎牵动全国人民的心&#xff0c;本项目希望通过大数据技术为抗击新冠肺炎贡献一份力量。 项目目标&#xff1a;使用PYTHON爬虫技术爬取疫情数据&#xff0c;从不同维度分析数据&#xff0c;并用 MATPLOT…

ubuntu18.04部署DXSLAM,CNN+VSLAM,CPU实时运行

一、下载源代码 打开终端&#xff0c;输入命令克隆仓库 git clone https://github.com/raulmur/DXSLAM.git DXSLAM二、配置环境 We have tested the library in Ubuntu 16.04 and Ubuntu 18.04, but it should be easy to compile in other platforms. C11 or C0x CompilerPa…

虚拟化技术学习笔记8

添加网卡&#xff1a; 1、virt-manager: 选择虚拟机直接添加网卡操作。 2、virsh命令&#xff1a; virsh list virsh domiflist centos7-1 virsh attach-interface centos7-1 \ --type network \ --source default \ --model virtio \ --config 虚拟机查看网卡的添加情况&…

分享65个NET源码,总有一款适合您

NET源码 分享65个NET源码&#xff0c;总有一款适合您 65个NET源码链接&#xff1a;https://pan.baidu.com/s/19yFm_9K_L0xfykMP1hdP5A?pwdn2p7 提取码&#xff1a;n2p7 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#x…

Apache APISIX Ingress 1.6 正式发布!

距离上一个版本 v1.5 发布&#xff0c;已经过了 3 个月&#xff0c;我们很高兴地宣布 Apache APISIX Ingress v1.6 正式发布&#xff01; 在该版本中&#xff0c;共有 29 位贡献者 参与代码提交&#xff0c;其中 17 位是新晋贡献者 &#xff0c;感谢大家的支持和参与&#xff…

nacos的服务注册与调用

此篇博客进行一个简单实例进行展示服务注册和服务的调用&#xff0c;以订单与库存模块为例&#xff0c;其结构图如下&#xff1a; 目 录 1、创建订单模块与库存模块 1.1、编写stock模块 1.2、编写order模块 2、访问地址进行测试 3、总结 1、创建订单模块与库存模块 创建两…

论文投稿指南——中文核心期刊推荐(生物科学 2)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

.net开发安卓入门-文件操作与配置操作

.net开发安卓入门-文件操作与配置操作文件操作内部存储代码运行效果System.Environment.SpecialFolder枚举类型对应路径表格外部存储&#xff08;代码和效果见上图&#xff09;区别缓存SharedPreferences获取SharedPreferences对象方法列表读取配置信息写配置信息AssetsNlog配置…

【Linux项目自动化构建工具 make/Makefile】

目录 1 背景 2 原理 3 Linux第一个小程序&#xff0d;进度条 3.1 行缓冲区概念 3.2 进度条代码 4 总结 1 背景 在VS中我们知道当我们想要运行程序时直接按f5程序就会自动运行起来&#xff0c;但是在Linux中如果有多个文件好像并不能这样快速进行&#xff0c;那么这时候就…

远程接入(远程办公)解决方案 OpenText™ Exceed™ TurboX (ETX)

OpenText™ Exceed™ TurboX 安全快速的虚拟应用程序和桌面解决方案&#xff0c;适用于混合工作环境&#xff0c;只需低带宽互联网连接即可为办公桌面和图形要求苛刻的软件提供卓越的用户体验。 突出优势&#xff1a; 支持混合云环境使用任何设备随时随地远程工作为用户提供类…

SpringCloud之Zuul路由网关

Zuul路由网关1. Zuul的概念2. Zuul的作用3. 案例1. Zuul的概念 Zuul包含了对请求的路由&#xff08;用来跳转的&#xff09;和过滤两个最主要功能&#xff1a; 其中路由功能负责将外部请求转发到具体的微服务实例上&#xff0c;是实现外部访问统一入口的基础&#xff0c;而过滤…

新年新故事 | Nice 兔 Meet U

各位伙伴新年好哇 比特熊又回来啦【比特熊故事汇2.0】23年开年第一场与大家一起认识“印象中”的不寻常开发人产品创新实践、工作 Mix 生活、反差感2023年1月12日19:00-20:00【比特熊故事汇2.0】新年想见你第一面Nice 兔 Meet U 比特熊兔年特别限定手办2023年兔年来到&#xff…

Ubuntu10.04编译libevent记录

目前有一个旧的程序 基于很老的ubuntu1004的系统做开发 很多新的C11什么的都用不了 之前 很多在ubuntu1804 上编译的so库 直接拿到1004上来用 提示报错 如下 没办法 只能重新在ubuntu 1004 上面编译了 记录下 下载libevent之后解压 直接执行./configure 提示报错如下图 …