数据结构之链表 - (通过代码实现方法,熟悉方法的使用)

news2025/1/12 1:02:27

文章目录

  • 前言
  • 1. 链表
    • 1.1 什么是链表?
    • 1.2 链表的分类
  • 2. 链表方法的实现
    • 2.1 实现构建思想
    • 2.2 代码实现
      • 2.2.1 实现方法前的准备工作
      • 2.2.2 链表方法:display() - 打印链表, contains() - 查找链表中key值, size() - 求链表长度
      • 2.2.3 头插法-addFirst(), 尾插法-addLast()
      • 2.2.4 addIndex-插入任意位置
      • 2.2.5 remove()-删除第一次遇到的值key,removeAllKey()-删除所有的值key
  • 总结

✨✨✨学习的道路很枯燥,希望我们能并肩走下来!

编程真是一件很奇妙的东西。你只是浅尝辄止,那么只会觉得枯燥乏味,像对待任务似的应付它。但你如果深入探索,就会发现其中的奇妙,了解许多所不知道的原理。知识的力量让你沉醉,甘愿深陷其中并发现宝藏。


前言

本篇通过写自己代码书写一些常用的方法,熟悉方法的使用,以至于使用方法时能够更好的操作。如有错误,请在评论区指正,让我们一起交流,共同进步!


本文开始

1. 链表

1.1 什么是链表?

链表:由一个一个节点组成,每个节点分为数据域(储存数据)和地址域(储存地址),连接节点是通过他们的地址。
链表特点:物理上不连续(与顺序表不同空间不是连续的),逻辑上连续;

1.2 链表的分类

链表分类图:

在这里插入图片描述

2. 链表方法的实现

2.1 实现构建思想

构建 MyLinkedList 链表(类),每个链表中一定有节点,而节点在Java中是类,每个类中赋值val,和记录下一个节点的地址next;定义一个head代表头节点的引用,从而操作链表;再在链表中实现常用的方法。

2.2 代码实现

2.2.1 实现方法前的准备工作

首先定义一个类MyLinkedList,在其中定义一个节点类Node;
再定义一个head节点,表示头节点的引用;
为什么使用再定义head : 操作实现链表的时候,我们都从head 开始 遍历至结束。

定义节点时为什么使用static?
这样在操作节点LinkNode时不需要依赖于对象(不需要new对象), 直接类名调用即可;

public class MyLinkedList {
    static class LinkNode {
        public int val;
        public LinkNode next;

        public LinkNode(int val) {
            this.val = val;
        }
    }
    public LinkNode head; //当前链表头结点的引用
 }

2.2.2 链表方法:display() - 打印链表, contains() - 查找链表中key值, size() - 求链表长度

遇到的问题:
遍历列表:涉及循环,为什么不使用head来遍历呢?、
定义变量 cur 来遍历,当head遍历完,head = null ,当再操作链表时无法再找到头部,所以需要一个变量来代替。(链表:这里举例的方法都需要这样)

遍历列表,需要找到结束条件;
这里需要清楚 cur.next != null 与 cur != null 的区别?
cur.next: 循环会停在链表最后一个的位置,指向节点的尾端; (少遍历一个)
cur = null: 所有元素遍历完全,最后指向空;

在这里插入图片描述

//遍历列表
    public void display(){
        LinkNode cur = head;
        //为啥不使用head遍历:head遍历完最后会为null,如果再遍历会找不到链表的头部,
        //所以我都会再定义一个遍历来操作链表,让head起到标记作用
        while(cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;//往后走一步
        }

    }
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        LinkNode cur = head;
        while (cur != null) {
            if(cur.val == key) { //找到值就返回ture
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
    //得到单链表的长度:需要遍历完链表
    public int size(){
        int num = 0;
        //num记录个数
        LinkNode cur = head;
        while (cur != null) {
            cur = cur.next;
            num++;
        }
        return num;
    }

2.2.3 头插法-addFirst(), 尾插法-addLast()

头插法:插在头的位置,所以每次需要更新一下头head;
首先生成一个需要插入的节点newLinkNode(new一下), 先连接后面的newLinkNode.next = cur.next,再更新head (head = newLinkNode);

在这里插入图片描述

头插代码:

 //头插法
    public void addFirst(int data){
        LinkNode newLinkNode = new LinkNode(data);
        newLinkNode.next = head;
        head = newLinkNode;
    }

尾插法:查找链表的尾部,每次需要先找到尾部,再插入;
思想:首先生成一个需要插入的节点newLinkNode(new一下),再找到最后一个节点cur.next == null,再连接cur.next = newLinkNode即可;

在这里插入图片描述

尾插代码:

  //尾插法
    public void addLast(int data){
        LinkNode newLinkNode = new LinkNode(data);
        if(head == null) {//如果一个节点也没有,插入的节点就是head
            head = newLinkNode;
            return;
        }
        //寻找链表尾部
        LinkNode cur = head;
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = newLinkNode;
    }

2.2.4 addIndex-插入任意位置

思想:首先判断插入的位置是否合法,考虑特殊情况(插入位置为首尾),找到要插入位置的前一个位置prvNode, 再连接;

//任意位置插入,第一个数据节点为0号下标
 public void addIndex(int index,int data){
        checkIndex(index);
        if(index == 0) {
            addFirst(data);
            return;
        }
        if(index == size()) {
            addLast(data);
            return;
        }
        LinkNode cur = findIndex(index);
        LinkNode newLinkNode = new LinkNode(data);
        newLinkNode.next = cur.next;//先连后面的
        cur.next = newLinkNode;
    }
    //返回发现的下标的节点地址
    private LinkNode findIndex(int index) {
        LinkNode cur = head;
        int num = 0;
        while (num != index - 1) {
            cur = cur.next;
            num++;
        }
        return cur;
    }
    private void checkIndex(int index) throws IndexOutOfExpection {
        if(index < 0 || index >= size()) {
            throw new IndexOutOfExpection("下标异常");
        }
    }

2.2.5 remove()-删除第一次遇到的值key,removeAllKey()-删除所有的值key

remove思想:考虑特殊情况,没有节点,节点只有一个;再定义一个方法findIndex()找到要删除的前一个节点prev, 再定义要删除的节点del,直接让prev.next = del.next (连接删除节点的下一个节点的地址);

 //删除第一次出现关键字为key的节点
    public void remove(int key){
        //一个节点都没有
        if(head == null) {
            return;
        }
        //有一个节点
        if(head.val == key) {
            head = head.next;
            return;
        }
        //findPrv : 发现要删除的数的前一个节点
        LinkNode prev = findPrv(key);
        //如果没找到返回null
        if(prev == null) {
            return;
        }
        LinkNode del = prev.next;
        prev.next = del.next;
    }
    private LinkNode findPrv(int key) {
        LinkNode cur = head;
        while (cur != null) {
            if(cur.next.val == key) {
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }

removeAllKey()
思想: 双指针操作, 首先定义两个指针prev,cur; cur指针用于遍历,prev用于记录位置, cur遍历时,如果遇到不是要删除的值,prev = next,跟随next一起走;如果遇到要删除的值,直接让prev指针连接cur指针的后一个节点(如果是连续的,cur会向后走一步直到不是要删除的值)当cur为空时,链表中的key值除头部全部删除完全;可以再判断一下第一个节点位置head.val == key;

//删除所有值为key的节点
    //思想:双指针删除所有key
    //双指针只能删除除head之外所有key
    //if第一个为要删除的key 最后需要单独处理一下,也可以开始时进行循环删除头
    public void removeAllKey(int key){
        if(head == null) {
            return;
        }
        LinkNode prev = head;
        LinkNode cur = head.next;
        while (cur != null) {
            if(cur.val == key) {
                prev.next = cur.next;
                cur = cur.next;
            } else {
                prev = cur;
                cur = cur.next;
            }
        }
        //单独处理头部
        if(head.val == key) {
            head = head.next;
        }
    }

总结

✨✨✨各位读友,本篇分享到内容如果对你有帮助给个👍赞鼓励一下吧!!
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!!

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

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

相关文章

比较生成模型

说说GAN/VAE/Flow/Diffusion/AR~~~ 各类生成模型&#xff0c;比如自回归模型Autoregressive Model (AR)&#xff0c;生成对抗网络Generative Adversarial Network (GAN)&#xff0c;标准化流模型Normalizing Flow (Flow)&#xff0c;变分自编码器Variational Auto-Encoder (VA…

软件测试优秀的测试工具,会用三款工作效率能提升一半

我们将常用的测试工具分为10类。 1. 测试管理工具 2. 接口测试工具 3. 性能测试工具 4. C/S自动化工具 5.白盒测试工具 6.代码扫描工具 7.持续集成工具 8.网络测试工具 9.app自动化工具 10.web安全测试工具 注&#xff1a;工具排名没有任何意义。 大多数初学者&…

图解Python深拷贝和浅拷贝

Python中&#xff0c;对象的赋值&#xff0c;拷贝&#xff08;深/浅拷贝&#xff09;之间是有差异的&#xff0c;如果使用的时候不注意&#xff0c;就可能产生意外的结果。 下面本文就通过简单的例子介绍一下这些概念之间的差别。 对象赋值 直接看一段代码&#xff1a; wil…

蓝桥杯:数字三角形

目录 题目描述 输入描述 输出描述 输入输出样例 输入 输出 思路&#xff1a; AC代码&#xff08;Java&#xff09;&#xff1a; 题目描述 上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径&#xff0c;把路径上面的数加起来可以得到一个…

数据结构基础--排序

一、直接插入排序 思路&#xff1a; 直接插入排序是一种简单的插入排序法 其基本思想是&#xff1a;把待排序的记录按其关键码值的大小逐个插入到一 个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 。 直接插入排序的特性总…

二分查找算法

目录 一 算法简介 1&#xff09;算法解释 2&#xff09;前提 3&#xff09;思想 4&#xff09;分类 5&#xff09;算法模板 mid的计算的实现方法 二分法模板 求某个数的平方根: 二 算法实践 1&#xff09;问题引入 2&#xff09;问题解答 1)解法一&#xff1a;左闭…

[附源码]Node.js计算机毕业设计关山社区居民信息管理系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

Nacos认证绕过漏洞(CVE-2021-29441)

Nacos认证绕过漏洞&#xff08;CVE-2021-29441&#xff09; 指纹识别 titlenacos漏洞范围 nacos1.2.0版本-nacos1.4.0版本 漏洞复现 靶机ip:192.168.1.4 默认的nacos登录界面 http://192.168.1.14:8848/nacos/#/login利用如下请求包查看只有一个nacos用户 GET /nacos/v…

ZBC陆续在主要CEX开启Staking,锁定市场大部分流通量成大利好

从2022年Q3开始&#xff0c;Zebec生态开始不断的迎来新的利好&#xff0c;比如以 10 亿美元的完全稀释估值筹集了 850 万美元&#xff0c;使其历史融资额超过4000万美元&#xff0c;引发ZBC通证的一波上涨。而在此后&#xff0c;Zebec 生态开启了从Solana生态的迁移&#xff0c…

Eclipse+Java+Swing+mysql实现学生宿舍管理系统

EclipseJavaSwingmysql实现学生宿舍管理系统一、系统介绍1.环境配置二、系统展示1.登录页2.学生主页面3.学生端-登记页面4.学生端-学生信息修改5.学生端-寝室信息查询6.学生端-学生信息查询7.学生端-退出登录8.管理员-主页面9.管理员-宿舍信息修改10.管理员-宿舍信息删除11.管理…

JQuery | 系统性学习 | 无知的我费曼笔记

无知的我已经复盘完成JQuery 。。。 文章目录JQuery概述入口函数特性-隐式迭代Dom和JQuery区别互相转化JQuery选择器基本和层级选择器筛选选择器后缀筛选方法筛选应用排他思想应用链式编程JQuery操作样式修改样式CSS修改类名JQuery效果基础效果显示效果隐藏效果切换效果滑动效果…

Springboot 使用redis检测浏览量,评论量,点赞量的变化并完成与mysql的交互(有具体实现,有具体需求)

目录 依赖 准备实体类与业务类 开始正题 实现一览 流程一览 具体实现 1 初始化 2 写浏览量增加的方法 3 在切面处检测浏览器变化 4 新增文章时将新的数据写入redis 5 删除文章时将数据从Redis中删除 6 书写将数据写入mysql数据库的方法 7 销毁的时候将数据写入my…

一文搞懂百万富翁问题

百万富翁问题1. 解决方案2. 协议描述3. 协议说明4. 协议举例两个百万富翁Alice和Bob想知道他们两个谁更富有&#xff0c;但他们都不想让对方及其他第三方知道自己财富的任何信息&#xff0c;这是由中国计算机科学家、2000年图灵奖获得者姚启智教授于1982年在论文《Protocols fo…

新手小白做跨境电商有哪些注意的地方?

近两年&#xff0c;受疫情刺激&#xff0c;线上电商出现前所未有的高速增长&#xff0c;中国品牌纷纷出海&#xff0c;跨境电商腾飞。此外&#xff0c;国内电商市场发展趋于平淡&#xff0c;市场需求不断萎缩&#xff0c;也让越来越多的大卖家和平台盯上了这块大蛋糕。不仅中小…

300左右半入耳蓝牙耳机推荐:南卡、漫步者、JBL蓝牙耳机谁值得入手?

现在的年轻人&#xff0c;出门都会随身携带的一副蓝牙耳机&#xff0c;所以很多品牌商加入其中&#xff0c;导致大多数人选购难度变大&#xff0c;很多人总是不知道哪个不知道品牌蓝牙耳机最好&#xff0c;半入耳式蓝牙耳机相比入耳式蓝牙耳机有着天然的舒适性&#xff0c;因而…

如何利用MOS管设计一个LED亮度可调电路

首先大家可以看下下面的MOS管亮度可调的演示视频 如何利用MOS管设计一个LED亮度可调电路这个电路大致电路图如下 MOS管的栅极放了一个电容&#xff0c;当按按键1的时候&#xff0c;电源通过R1给电容充电&#xff0c;&#xff0c;MOS管栅极的电压慢慢增大&#xff0c;流过MOS管的…

计算机毕业设计HTML+CSS+JavaScript——基于HTML花店购物网站项目的设计与实现

常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他等网页设计题目, A…

Essential singularity

In complex analysis, an essential singularity of a function is a “severe” singularity near which the function exhibits odd behavior. The category essential singularity is a “left-over” or default group of isolated singularities that are especially unm…

跳转指令 —— B、BL

跳转指令可以跳转到标号的下一条指令&#xff0c;本质就是修改了PC寄存器的值。&#xff08;标号并非指令&#xff0c;只是用来定位&#xff0c;相当于记录了当前位置的下一条指令的地址&#xff09; 这里的MAIN就是一个标号 MAIN: MOV R1, #1 这里的FUNC就是一个标…

实验3 路由器基本配置及路由配置

实验3 路由器基本配置及路由配置一、实验目的二、实验要求三、实验步骤&#xff0c;数据记录及处理四&#xff0e;实验总结一、实验目的 1、路由器几种模式。 2、基本的配置命令。 3、路由器各接口的配置方法。 4、会查看检测接口状态。 二、实验要求 写出自己学习使用了哪些…