数据结构--线性表双向链表的实现

news2024/11/25 15:25:48

目录

思路设计

总体思维导图

插入部分

头插法+尾插法

任意位置插入

删除部分

头结点

尾节点

中间节点

只有头结点且删除的就是头结点

​编辑

清空链表部分

遍历清空链表的所有节点

不遍历清空

各部分代码

Main部分

MyListedList部分

IndexOutOfException部分

总结


思路设计

设计Main,MyListedList,IndexOutOfException 三个文件。

Ma负责主函数的运行,MyList负责各种方法,IndexOut负责输入错误的提示。

总体思维导图

插入部分

头插法+尾插法

任意位置插入

删除部分

头结点

尾节点

中间节点

只有头结点且删除的就是头结点

清空链表部分

遍历清空链表的所有节点

不遍历清空

各部分代码

Main部分

public class Main {
    public static void main(String[] args) {
        //这个是顺序表的写法,现在是双向链表
        //MyListedList<Integer> myListedList= new MyListedList();

        MyListedList myListedList= new MyListedList();

        myListedList.addFirst(1);
        myListedList.addFirst(2);
        myListedList.addFirst(3);
        myListedList.addFirst(4);

        /*myListedList.addLast(1);
        myListedList.addLast(2);
        myListedList.addLast(3);
        myListedList.addLast(4);*/


        //System.out.println(myListedList.size());
        //System.out.println(myListedList.contains(10));
        //myListedList.display();

        //myListedList.addIndex(0,99);
        //myListedList.display();

        myListedList.removeAllKey(1);
        myListedList.clear();
        myListedList.display();

    }
}

MyListedList部分

public class MyListedList {

    static class ListNode{
        private int val;
        private ListNode prev;
        private ListNode next;

        //重写构造方法得以调用
        //才能保证下面传入的data能使用
        //ListNode node = new ListNode(data);
        public ListNode(int val) {
            this.val = val;
        }
    }

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

    //得到单链表的长度
    //size,display,contains都是要遍历定义头指针
    public int size(){
        ListNode cur = head;
        int count = 0;
        while (cur != null){
            count++;
            cur = cur.next;
        }

        return count;
    }

    public void display(){
        //遍历定义一个头结点指针,让其不断往后走
        ListNode cur = head;
        while (cur != null){
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }

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


        //头插法
        public void addFirst(int data){
            ListNode node = new ListNode(data);

            //如果插入的节点的前后指针都是空的话
            //要修改链表里面的头尾指针
            if(head == null){
                head = node;
                last = node;
            }else {
                //先改变next再改变perv
                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;
                //或者 last = last.next
            }
        }
        //任意位置插入,第一个数据节点为0号下标
        public void addIndex(int index,int data){
            checkIndex(index);

            if(index == 0){
                addFirst(data);
                return;
            }

            if(index == size()){
                addLast(data);
                return;
            }

            //声明cur
            ListNode cur = seachIndex(index);
            ListNode node = new ListNode(data);
            node.next = cur;
            cur.prev.next = node;
            node.prev = cur.prev;
            cur.prev = node;

        }

        //定义cur找到插入的位置
        private ListNode seachIndex(int index){
            ListNode cur = head;

            while (index != 0){
                cur = cur.next;
                index--;
            }
            return cur;
        }

        private void checkIndex(int index){
            if (index < 0 || index > size()){
                //可以自定义抛出RuntimeException(运行异常)一个异常

                throw new IndexOutOfException("index 不合法!"+index);

            }
        }

        //删除第一次出现关键字为key的节点
        public void remove(int key){

            ListNode cur = head;
            if(head == null) {
                head = cur;
                last = cur;
            }

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

                    }
                    return;
                }else {
                    cur = cur.next;
                }

            }

        }
        //删除所有值为key的节点
        public void removeAllKey(int key){
            ListNode cur = head;
            if(head == null) {
                head = cur;
                last = cur;
            }

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

                    }
                    //删除key数据了之后往后走,查看
                    //是否还有要删除的数据去遍历
                    cur = cur.next;
                    //return;
                }else {
                    //就算这个数据不是我要删除的数据,我也往后走去遍历
                    cur = cur.next;
                }

            }
        }

        public void clear(){

            ListNode cur = head;

            while (cur != null){
                ListNode curNext = cur.next;
                if(cur == null){
                    cur = curNext;
                }else {
                    cur.next = null;
                    cur.prev = null;
                    cur = curNext;
                }
            }
            head = null;
            last = null;
        }
}

IndexOutOfException部分

public class IndexOutOfException extends RuntimeException{

    //提供两个构造方法
    public IndexOutOfException() {
    }

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

总结

部分方法大体上写法都大致相同,关键在于具体方法部分,比如:删除的节点就只有一个,而且这个要删除的节点就是头结点,那么这种特殊情况是在写完正常删除操作后,输入数据判断得到的结果,针对这样的情况要画图分析,一步一步慢慢思考如何设计程序代码,出错没有关系,再次调试画图看看有没有漏掉的地方,一次次修改相信最终会获得成功完成任务的代码。

数据结构的核心就是,代码容易写,思考最难想的一个学习过程,由此可见画图在帮助我们理清思路,规整代码写法的时候就尤为重要!


希望这篇博客能给读者在学习数据结构时提供一些帮助。

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

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

相关文章

微软发布Windows 11 2024更新,新型Copilot+ AI PC功能亮相

前言 微软在Windows 11的2024更新中加强了对人工智能的应用&#xff0c;推出了新功能Copilot。 此次更新的版本号为26100.1742&#xff0c;Copilot将首先在Windows Insider中推出&#xff0c;计划于11月向特定设备和市场推广&#xff0c;用户需开启“尽快获取最新更新”选项以…

Eureka的搭建、注册和拉取

目录 搭建 动手实践 搭建EurekaServer 创建项目 编写启动类 添加application.yml文件 启动EurekaApplication ​编辑 总结 搭建EurekaServer 注册 将user-service服务注册到EurekaServer 将order-service服务注册到EurekaServer 重启order-service和user-service…

敢为天下先:论特斯拉轿车设计理念和六西格玛设计方法的应用-张驰咨询

全球竞争日益激烈的电动汽车市场&#xff0c;特斯拉通过其独特的设计理念和创新能力脱颖而出。其核心驱动因素之一&#xff0c;是特斯拉在设计和制造中的第一性原理**&#xff08;First Principles&#xff09;思维&#xff0c;以及通过应用六西格玛设计方法实现的高质量制造流…

YoloV10改进策略:BackBone改进|CAFormer在YoloV10中的创新应用,显著提升目标检测性能

摘要 在目标检测领域,模型性能的提升一直是研究者和开发者们关注的重点。近期,我们尝试将CAFormer模块引入YoloV10模型中,以替换其原有的主干网络,这一创新性的改进带来了显著的性能提升。 CAFormer,作为MetaFormer框架下的一个变体,结合了深度可分离卷积和普通自注意力…

51c自动驾驶~合集2

我自己的原文哦~ https://blog.51cto.com/whaosoft/11491137 #BEVWorld BEV潜在空间构建多模态世界模型&#xff0c;全面理解自动驾驶~一、引言 世界模型建模了有关环境的知识&#xff0c;其可以通过给定的条件对未来进行合理的想象。未来想象要求世界模型具有物理规律的理解…

五万字综述!Prompt Tuning:深度解读一种新的微调范式

导读 本文将深入解读Prompt-Tuning的微调范式&#xff0c;以综述讨论的形式展开。 \ 这绝对是我看过最全面细致的Prompt Tuning技术综述之一&#xff0c;全文共五万多字&#xff0c;看完之后你一定发出一样的感叹&#xff01; 阅读该博客&#xff0c;您将系统地掌握如下知识…

【操作系统】虚拟机

&#x1f339;&#x1f60a;&#x1f339;博客主页&#xff1a;【Hello_shuoCSDN博客】 ✨操作系统详见 【操作系统专项】 ✨C语言知识详见&#xff1a;【C语言专项】 首先先来了解传统的计算机 在生产的时候&#xff0c;物理机器&#xff08;硬件&#xff09;其实是非常强大的…

32 基于51单片机的电机控制和角度检测

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采用滑动变阻器连接ADC0832数模转换器模拟角度传感器&#xff0c;然后通过LCD1602显示数值&#xff0c;然后按键按下不动&#xff0c;电机正转&#xff0c;松开停止。第二…

DHCP Snooping典型配置举例(如何防止路由器乱接问题)

全局开启DHCP Snooping配置举例 组网需求 Router B通过以太网端口Ten-GigabitEthernet0/0/6连接到合法DHCP服务器&#xff0c;通过以太网端口Ten-GigabitEthernet0/0/8连接到非法DHCP服务器&#xff0c;通过Ten-GigabitEthernet0/0/7连接到DHCP客户端。要求&#xff1a; 与合…

33 基于单片机的智能窗帘控制系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采用DHT11温湿度传感器检测温湿度&#xff0c;滑动变阻器连接ADC0832数模转换器转换模拟,光敏传感器&#xff0c;采用GP2D12红外传感器&#xff0c;通过LCD1602显示屏显示…

嵌入式硬件设计知识详解

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

015 品牌关联分类

文章目录 后端CategoryBrandEntity.javaCategoryBrandController.javaCategoryBrandServiceImpl.javaCategoryServiceImpl.javaBrandServiceImpl.java删除 npm install pubsub-jsnpm install --save pubsub-js这个错误是由于在尝试安装 pubsub-js 时&#xff0c;npm 发现了项目…

Python 如何使用 multiprocessing 模块创建进程池

Python 如何使用 multiprocessing 模块创建进程池 一、简介 在现代计算中&#xff0c;提升程序性能的一个关键方法是并行处理&#xff0c;尤其是当处理大量数据或计算密集型任务时&#xff0c;单线程可能不够高效。Python 提供了多个模块来支持并行计算&#xff0c;其中最常用…

爬虫案例——爬取长沙房产网租房信息

需求&#xff1a; 1.爬取长沙房产网租房信息&#xff08;长沙租房信息_长沙出租房源|房屋出租价格【长沙贝壳租房】 包括租房标题、标题链接&#xff0c;价格和地址 2.实现翻页爬取 3.使用bs4解析数据 分析 1.抓取正确的数据包——看响应内容 找到正确的后&#xff0c;复…

大模型之RAG-关键字检索的认识与实战(混合检索进阶储备)

前言 按照我们之前的分享&#xff08;大模型应用RAG系列3-1从0搭建一个RAG&#xff1a;做好文档切分&#xff09;&#xff1a; RAG系统搭建的基本流程 准备对应的垂域资料文档的读取解析&#xff0c;进行文档切分将分割好的文本灌入检索引擎&#xff08;向量数据库&#xff…

如何使用ssm实现新冠病毒校园监控平台的设计与实现+vue

TOC ssm812新冠病毒校园监控平台的设计与实现vue 绪论 课题背景 身处网络时代&#xff0c;随着网络系统体系发展的不断成熟和完善&#xff0c;人们的生活也随之发生了很大的变化。目前&#xff0c;人们在追求较高物质生活的同时&#xff0c;也在想着如何使自身的精神内涵得…

python画图|曲线动态输出基础教程

在前述学习过程中&#xff0c;已经掌握基本的曲线图像画法&#xff0c;并尝试探索过3D动画基础教程。 相关文章可以通过下述链接直达&#xff1a; python画三角函数图|小白入门级教程_正余弦函数画图python-CSDN博客 python动画教程|Animations using Matplotlib-官网教程程…

Hallo部署指南

一、介绍 Hallo是由复旦大学、百度公司、苏黎世联邦理工学院和南京大学的研究人员共同提出的一个AI对口型肖像图像动画技术&#xff0c;可基于语音音频输入来驱动生成逼真且动态的肖像图像视频。 该框架采用了基于扩散的生成模型和分层音频驱动视觉合成模块&#xff0c;提高了…

Linux实践|设置静态 IP 地址

引言 如果您是 Linux 系统管理员&#xff0c;那么您将需要在系统上配置网络。与可以使用动态 IP 地址的台式机不同&#xff0c;在服务器基础设施上&#xff0c;您需要设置静态 IP 地址&#xff08;至少在大多数情况下&#xff09;。 本文[1]旨在向您展示如何在最常用的 Linux 发…

TBD62783AFG的强大性能:高性能应用的可靠解决方案

在当今竞争激烈的电子市场中&#xff0c;工程师们始终在寻找能够提供可靠性、效率和多功能性的组件&#xff0c;尤其是在处理复杂、高性能系统时。东芝的TBD62783AFG 8通道源型DMOS晶体管阵列就是这样一个元件。凭借其独特的功能组合&#xff0c;使其成为从小型电机到感性设备的…