初见 链表

news2024/9/20 1:09:44

前言

在上篇文章重温数组——顺序表  http://t.csdnimg.cn/9DH9M 后,本篇文章让我们认识一种新的数据结构:链表

认识

概念:链表是⼀种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表 中的指针链接次序实现的。

何为链表?可以去和生活中的火车类比,每一节火车车厢都有下一节车厢的钥匙,这样一来,可以看下图,其中上面便是我们所存储的数据,而下面便是连接彼此的“钥匙”。

单拿一个出来看,这一个一个便是 节点,当前节点主要有两个部分组成:要保存的数据和保存下一个节点的地址,这边是连接的关键,需要保存下一个节点的地址才能找到下一个节点,

其中有这么一个节点--头结点head去指向我们所存储的第一个节点,因此头结点中无论存了什么数据都是没有意义的

链表的种类不止我所举例的这一种,可以根据三个特征,单向还是双向,带头还是不带头,循环还是不循环来分类,但本文章主要介绍的是单向 不带头 不循环的链表哦~

基本功能实现

我们类比着顺序表来学,来实现相同的功能

首先初始化一个链表

那就少不了头结点head,要存放的数据data,以及让节点间产生联系的引用next ,在构造方法中让next置为0,那样只有一个节点的链表就创建成功了~

    private Node head;//首先定义一个头结点(节点类型)
    private static class Node {
        int data; // 节点数据
        Node next; // 下一个节点的引用

        Node(int data) {//构造方法
            this.data = data;
            this.next = null;//表示当前节点是最后一个节点
        }
    }

打印链表

同样也是少不了遍历,那我们想想1.怎么从第一个节点走到第二个节点?2.遍历什么时候结束?

首先别忘记了head的作用!于是head=head.next便可以遍历全部节点,那最后一个节点没有指向(单向)不就是null吗?如此一来

 public void display(){
     Node current =head;//避免改变头指针的位置
     while(current!=null){
         System.out.println(current.data+' ');
         current=current.next;//遍历所有节点
     }
     System.out.println();
 }

这里要特别注意:为啥不能用current.next呢?那是因为next本就是指向下一个数据,这样的话就会少遍历一个数据,即是current本身

清空链表

既然要做一个空链表,那想想刚创建链表的时候head的作用,只要让head头结点置null,那是不是就空了?可不能又是head.next置空~

 public void clear(){
     head=null;
 }
获得单链表的长度
public int size(){
    int count = 0;//用于记录链表长度
    Node current = head;//避免改变head的位置
    while(current != null){
        count++;
        current = current.next;
    }
    return count;
}

四大功能的实现

4.1 数据的添加之头插法

先给新节点new一个对象,让新节点的next指向原本的头,新节点设为新的头,结合图解和代码就更好理解了~

public void addFirst(int data){
    Node node = new Node(data);
    node.next = head; // 将新节点的next指向原来的头节点
    head = node; // 更新head节点为新插入的节点
}

4.2尾插法

有头插必有尾插,首先要找到链表的尾巴,找到后让next等于新插入的节点即可,不过这里就要考虑特殊情况了,假设是一个空链表,那头插和尾插其实就没区别了

 //尾插法
 public void addLast(int data) {
     Node newNode = new Node(data);
     if (head == null) {//如果头是空
         head = newNode;
     } else {
         Node current = head;
         while (current.next != null) {
             current = current.next;//遍历链表
         }
         current.next = newNode;//添加进去
     }
 }

4.3 任意位置插入

既然插入的是任意位置,那头插和尾插都要考虑,还有插入位置的合法性等等,这些都是特殊情况,那一般的插入配合画图就好理解了。遍历的过程中找到要插入的位置的前一个节点方便插入,因为链表插入是不需要移动元素的,改变next的指向就行

    public void addIndex(int index, int data) {
        Node current = head; // 定义current代替head去遍历
        if (index < 0 || index > size()) { // 判断插入位置是否合法
            return ; // 如果位置不合法,直接返回
        } else if (index == 0) { // 插入位置为链表头部
            addFirst(data); // 调用addFirst方法添加到链表头部
        } else if (index == size()) { // 插入位置为链表尾部
            addLast(data); // 调用addLast方法添加到链表尾部
        } else {
            int count = 0; // 记录当前节点位置
            while (count != index - 1) { // 找到指定位置的前一个节点
                current = current.next; // 移动到下一个节点
                count++;//这样就会逐步趋近index-1
            }
            Node node = new Node(data); // 创建新节点
            node.next = current.next; // 新节点的next指向原来链表中该位置的节点
            current.next = node; // 原来该位置节点的next指向新节点,完成插入操作
        }
    }

 在图中,本来current.next是指向0x89的,但是赋值给新node.next,这样就完成了第一步

第二步就改变current.next为node就行

所以在插入的过程中,发现了一个规律:先绑定后面的指向,再修改前面的指向。这样就保证了连贯性!

4.4删除第一次出现关键字key的节点

找到要删除的前一个节点,这样就不会丢失current了,同样的,一些极端情况也要考虑,如果第一个节点就是要删的,那么直接head赋值成head.next ,这样头结点就被删掉了

public void remove(int key) {
    while (head != null && head.data == key) {
        head = head.next; // 处理头节点为 key 的情况
    }

    Node current = head;
    while (current != null && current.next != null) {
        if (current.next.data == key) {
            current.next = current.next.next; // 删除当前节点的下一个节点
        } else {
            current = current.next;
        }
    }
}

4.5删除所有关键字key的节点

在删除第一个的基础上继续循环,这样便能实现啦!

public void removeAllKey(int key) {
    // 处理头节点为 key 的情况,一直删除直到头节点不为 key
    while (head != null && head.data == key) {
        head = head.next;
    }

    Node current = head;
    while (current != null && current.next != null) {
        // 判断当前节点的下一个节点是否为 key
        if (current.next.data == key) {
            // 将当前节点的 next 指针指向下一个节点的下一个节点,跳过要删除的节点
            current.next = current.next.next;
        } else {
            // 如果下一个节点不为 key,继续遍历链表,直到删完为止
            current = current.next;
        }
    }
}

4.6查询链表是否包含指定的关键字key

对于关键字的匹配和打印差不多,加个判断条件就行,代码奉上~

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

链表的基础知识就分享到这里,希望看到这里的你收获满满~

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

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

相关文章

【JavaEE】进程是什么?

文章目录 ✍进程的概念✍进程存在的意义✍进程在计算机中的存在形式✍进程调度 ✍进程的概念 每个应⽤程序运⾏于现代操作系统之上时&#xff0c;操作系统会提供⼀种抽象&#xff0c;好像系统上只有这个程序在运⾏&#xff0c;所有的硬件资源都被这个程序在使⽤。这种假象是通…

360奇酷刷机 360刷机助手 QGDP360手机QGDP刷机

360奇酷刷机 360刷机助手 QGDP破解版360手机QGDP刷机 360手机刷机资源下载链接&#xff1a;360rom.github.io 参考&#xff1a;360手机-360刷机360刷机包twrp、root 360奇酷刷机&#xff1a;360高通驱动安装 360手机刷机驱动&#xff1b;手机内置&#xff0c;可通过USB文件传输…

修改 RabbitMQ 默认超时时间

MQ客户端正常运行&#xff0c;突然就报连接错误&#xff0c; 错误信息写的很明确&#xff0c;是客户端连接超时。 不过很疑虑&#xff0c;为什么会出现连接超时呢&#xff1f;代码没动过&#xff0c;网络也ok&#xff0c;也设置了心跳和重连机制。 最终在官网中找到了答案&am…

『笔记』可扩展架构设计之消息队列

前言 众所周知&#xff0c;开发低耦合系统是软件开发的终极目标之一。低耦合的系统更加容易扩展&#xff0c;低耦合的模块更加容易复用&#xff0c;更易于维护和管理。我们知道&#xff0c;消息队列的主要功能就是收发消息&#xff0c;但是它的作用不仅仅只是解决应用之间的通…

java一和零(力扣Leetcode474)

一和零 力扣原题 给定一个二进制字符串数组 strs 和两个整数 m 和 n&#xff0c;请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中最多有 m 个 0 和 n 个 1。 示例 1&#xff1a; 输入&#xff1a;strs [“10”, “0001”, “111001”, “1”, “0”], m 5, n …

基于GA优化的CNN-LSTM-Attention的时间序列回归预测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1卷积神经网络&#xff08;CNN&#xff09;在时间序列中的应用 4.2 长短时记忆网络&#xff08;LSTM&#xff09;处理序列依赖关系 4.3 注意力机制&#xff08;Attention&#xff09; 5…

基于BP神经网络的城市空气质量数据预测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 BP神经网络结构 4.2 神经元模型与激活函数 4.3 前向传播过程 4.4反向传播算法及其误差函数 4.5 权重更新规则 4.6 迭代训练 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软…

Qt_day4:2024/3/25

作业1&#xff1a; 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和…

一篇文章,告别Flutter状态管理争论,问题和解决

起因 每隔一段时间&#xff0c;都会出现一个新的状态管理框架&#xff0c;最近在YouTube上也发现了有人在推signals, 一个起源于React的状态管理框架&#xff0c;人们总是乐此不疲的发明各种好用或者为了解决特定问题而产生的方案&#xff0c;比如Bloc, 工具会推陈出新&#x…

qt table 简易封装,样式美化,以及 合并表格和颜色的区分 已解决

在需求中&#xff0c; 难免会使用 table 进行渲染窗口&#xff0c;做一个简单的封装。美化表格最终效果&#xff01;&#xff01;&#xff01; 代码部分 // 显示 20行 20列CCendDetailsInfoTableWidget* table new CCendDetailsInfoTableWidget(20,10);for (int i 0; i < …

ESCTF-逆向赛题WP

ESCTF_reverse题解 逆吧腻吧babypybabypolyreeasy_rere1你是个好孩子完结撒花 Q_W_Q 逆吧腻吧 下载副本后无壳&#xff0c;直接拖入ida分析分析函数逻辑&#xff1a;ida打开如下&#xff1a;提取出全局变量res的数据后&#xff0c;编写异或脚本进行解密&#xff1a; a[0xBF, …

enscan自动化主域名信息收集

enscan下载 Releases wgpsec/ENScan_GO (github.com) 能查的分类 实操&#xff1a; 首先打开linux 的虚拟机、 然后把下面这个粘贴到虚拟机中 解压后打开命令行 初始化 ./enscan-0.0.16-linux-amd64 -v 命令参数如下 oppo信息收集 运行下面代码时 先去配置文件把coo…

JavaEE企业开发新技术3

目录 2.11 Method的基本操作-1 文字性概念描述 代码&#xff1a; 2.12 Method的基本操作-2 2.13 Method的基本操作-3 2.14 数组的反射操作-1 文字性概念&#xff1a; 代码&#xff1a; 2.15 数组的反射操作-2 学习内容 2.11 Method的基本操作-1 文字性概念描述 Me…

io的学习4

打印流 分类&#xff1a;打印流一般是指&#xff1a;PrintStream、PrintWriter两个类 特点&#xff1a; 1.打印流只操作文件目的地&#xff0c;不操作数据源 2.特有的写出方法可以实现&#xff0c;数据原样写出 3.特有的写出方法&#xff0c;可以实现自动刷新&#xff0c;…

仅用一个月,游卡完成从MySQL到上线OceanBase的实践

编者按&#xff1a;自2023年9月起&#xff0c;游卡——国内最早卡牌游戏研发者之一&#xff0c;开始测试OceanBase&#xff0c;并在短短两个月内成功将三个核心业务应用迁移至OceanBase上。究竟是何因素促使游卡放弃游戏行业普遍采用的MySQL方案&#xff0c;转而大胆选择OceanB…

荟萃分析R Meta-Analyses 3 Effect Sizes

总结 效应量是荟萃分析的基石。为了进行荟萃分析&#xff0c;我们至少需要估计效应大小及其标准误差。 效应大小的标准误差代表研究对效应估计的精确程度。荟萃分析以更高的精度和更高的权重给出效应量&#xff0c;因为它们可以更好地估计真实效应。 我们可以在荟萃分析中使用…

一文整合工厂模式、模板模式、策略模式

为什么使用设计模式 今天终于有时间系统的整理一下这几个设计模式了&#xff0c; 这几个真是最常用的&#xff0c;用好了它们&#xff0c;你就在也不用一大堆的if else 了。能更好的处理大量的代码冗余问题。 在我们的实际开发中&#xff0c;肯定会有这样的场景&#xff1a;我…

【C语言基础】:内存操作函数

文章目录 一、memcpy函数的使用和模拟实现1.1 memcpy函数的使用1.2 memcpy函数的模拟实现 二、memmove函数的使用和模拟实现2.1 memmove函数的使用2.2 memmove函数的模拟实现 三、memset函数的使用3.1 menset函数的使用 四、memcmp函数的使用4.1 memcmp函数的使用 学海无涯苦作…

Qt与编码

ASCII码:一个字节&#xff0c;256个字符。 Unicode:字母&#xff0c;汉字都占用两个字节。 utf-8:字母一个字节&#xff0c;汉字3个字节。 gbk:字母一个字节&#xff0c;汉字2个字节。 gb2312:可以表示汉字&#xff0c;gb2312<gbk。 编码查看&#xff1a; https://www.…

钡铼技术R40路由器助力构建无人值守的智能化污水处理厂

钡铼技术R40路由器作为智能化污水处理厂的关键网络设备&#xff0c;发挥着至关重要的作用&#xff0c;助力构建无人值守的智能化污水处理系统。在现代社会&#xff0c;污水处理是城市环境保护和可持续发展的重要组成部分&#xff0c;而智能化污水处理厂借助先进的技术和设备&am…