数据结构-链表结构-单向链表

news2024/10/6 5:58:41

链表结构

说到链表结构就不得不提起数据结构,什么是数据结构?就是用来组织和存储数据的某种结构。那么到底是某种结构呢?

数据结构分为:

  • 线性结构
    • 数组,链表,栈,队列
  • 树形结构
    • 二叉树,B树,红黑树等
  • 图形结构
    • 邻接矩阵,邻接表等

那么链表就是我们这节课的主角,之前其实我们都接触过链表就是集合中基于List实现的linkedlist,但是在练习的过程中我发现好多同志只会用,不知道其中原理,知其然而不知其所以然。但是也会有同志说了我会用不就不就醒了,各位凡是要做到精益求精,知其然跟要知其所以然。为实现科技报国我们的祖国就需要这种人才,一起创新创建共创科技大国。

链表结构的定义

什么是链表

在逻辑结构上一个挨一个的数据,但是在实际存储时所在的内存地址却并不连续,相反数据随机分布在内存中的各个位置。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uo1YfDER-1690775932877)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731093517699.png)]

通过数据的指针指向下一个数据,这种存储结构称为链式存储,而这种链式存储所生成的表就是链表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-63Npk2QJ-1690775932878)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731093456452.png)]

链表分类

  • 单向链表
  • 双向链表
  • 双向循环链表

单向链表

什么是单向链表

上面说到了什么是链表,那么在单向链表中我们将数据分为两个区域

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WFVtGpFY-1690775932878)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731095437329.png)]

在链表中它有一个专业名字叫做:节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4HrBVGMO-1690775932879)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731095418610.png)]

一个节点指向下一个节点,这种链式结构称为单向链表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DaVYtHbB-1690775932879)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731095536584.png)]

在单向链表中,链表的第一个节点称为首元节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LVWMVy6h-1690775932880)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731095809932.png)]

链表的最后一个节点称为尾节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RExs1D0C-1690775932880)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731095856557.png)]

中间的这个节点的前一个节点称为前驱

![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h7w71tre-1690775932881)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731100016010.png)](https://img-blog.csdnimg.cn/a07cd1f5d2d74d5f9dfe5dde41da8c4b.png)

中间的这个节点的后一个节点称为后继

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mg6JU2zh-1690775932881)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731100047613.png)]

通常在链表的前面会有一个节点称为头节点,当然头节点不是必须存在的。

  • 头节点的作用是:用来存储链表的长度

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jXLTPxvG-1690775932882)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731100239606.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-29rianmB-1690775932882)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731100320069.png)]

在每一个链表中都会配备一个头指针,指针始终指向第一个节点,如果有链表中配备头节点则指向头节点,如果没有配备头节点则指向首元节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dTTJDnYf-1690775932883)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731100533063.png)]

头指针的定义是:用于在链表中挪动指针查找数据,直到找到对应的数据

在这里插入图片描述

单向链表的功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FPscmp6z-1690775932884)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731103625505.png)]

    • 向链表的尾节点添加节点

      • 将新添加节点的内存地址存放到该链表尾节点的指针域中。通俗的讲:将尾节点的指针域指向新添加的节点

      • 此时尾节点就是新添加的这个节点

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EOecEUmO-1690775932884)(E:\Java笔记\数据结构\线形结构\链表结构.assets\20230731_104622.gif)]

    • 向链表的首元节点之前添加节点

      • 将链表的首元节点的内存地址存放到新添加节点的指针域中。通俗的讲:新节点的指针指向首元节点

      • 此时首元节点是新添加的这个节点

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NGbrG5IA-1690775932885)(E:\Java笔记\数据结构\线形结构\链表结构.assets\20230731_105455.gif)]

    • 向链表中间添加节点

      • 将新添加节点的内存地址存放到前驱的指针域中,新添加节点的指针域存放后继的内存地址。通俗的讲:修改前驱的指针方向指向新添加的节点,新添加的节点执行后继即可

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4JmT2yty-1690775932885)(E:\Java笔记\数据结构\线形结构\链表结构.assets\20230731_110227.gif)]

    • 删除尾节点

      • 尾节点的前驱的指针域不在存储尾节点的内存地址。通俗的讲:尾节点的指针域不在指向尾节点
    • 删除首元节点

      • 首元节点的指针域不存放后继的内存地址。通俗的讲:首元节点的指针与不在指向后继节点
    • 删除中间的某个节点

      • 删除节点的前驱指针域不再存放删除节点的内存地址,删除节点的指针域不再存储后继的内存地址,通俗的讲:删除节点的前驱指向删除节点的后继

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jK3f0kcV-1690775932886)(E:\Java笔记\数据结构\线形结构\链表结构.assets\20230731_110948-16907732210771.gif)]

      注意:被删除的节点称之为:野节点,这并不是真正意义上的删除,它在内存中依旧存在。那么野节点的最终归宿是被JVM的GC(垃圾回收器)所回收,也就是释放该节点的内存空间,这才是真正意义上的删除

      额外知识:java中的垃圾回收器(Garbage Collector,GC)负责管理内存的分配和释放。当一个对象没有任何引用指向它时,它就变得不可达,而垃圾回收器会将其标记为垃圾对象,并在适当的时候回收该对象所占用的内存空间。这个过程称为垃圾回收。

    • 挪动指针找到要修改的节点,之后讲修改节点的数据域中的数据修改掉
    • 挪动指针找到要所要查找的数据。

特点

  • 节点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻。

  • 数据元素的个数可以自由扩充,插入,删除,只需要修改节点的指针方向,效率高

  • 修改和查找节点数据需要挪动指针,按照节点的顺序进行依次查找或者修改,效率比较低

与数组的区别

回顾数组

数组的功能

    • 数据不能超过定义的数组长度
    • 数据少于定义数组的长度会造成内存浪费
    • 数组中间添加数据会将之后的数据内存位置往后挪动

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rbC5fv9m-1690775932886)(E:\Java笔记\数据结构\线形结构\链表结构.assets\20230731_115259.gif)]

区别

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kpln7pfQ-1690775932886)(E:\Java笔记\数据结构\线形结构\链表结构.assets\image-20230731115828188.png)]

实现单项链表

MyList
/**
 * @CreateName SIN
 * @CreateDate 2023/07/27 16:28
 * @description 定义链表功能规范,避免子类编码随意性。同时也实现了程序的解耦,提高代码的可维护性。
 */
//泛型E任何数据类型
public interface MyList<E> {
    //添加节点数据
    void add(E element);
    //获取节点数据(根据具体的指针找到对应的数据)
    E get(int index);
    //获取链表的长度
    int size();
    //根据指针移除节点
    E remove(int index);
    //修改节点数据
    E set(int index,E element);
}

MyLinkedList
package com.sin.linkedList;

/**
 * @CreateName SIN
 * @CreateDate 2023/07/27 16:35
 * @description
 */
public class MyLinkedList<E> implements MyList<E>{

    // 存放链表的头节点
    private Node head;

    // 记录链表的长度
    private int size;

    /**
     * 向链表中添加节点
     * @param element 添加的节点
     */
    @Override
    public void add(E element) {
        //创建一个新的节点,存储传入的元素
        Node<E> node = new Node<E>(element,null);
        //获取链表尾节点
        Node tail = getTail();
        //如果链表为空,
        if (tail == null){
            //将新节点设置为头节点
            this.head = node;
        }else{
            //否则,在尾节点后面添加新节点
            tail.next = node;
        }
        //记录元素的个数
        this.size++;
    }

    /**
     * 获取尾节点
     * @return 返回尾节点
     */
    private Node getTail(){
        //判断当前头节点是否为空
        if(this.head == null){
            return null;
        }
        //遍历链表
        //从头节点开始遍历链表
        Node node = this.head;
        while (true){
            //如果下一个节点为空,则表示当前节点为尾节点,则跳出循环
            if(node.next == null){
                break;
            }
            //在循环的过程中,移动指针,指向下一个节点
            node = node.next;
        }
        //返回尾节点
        return node;
    }

    /**
     * 根据指针获取节点数据
     * @param index
     * @return 返回节点数据
     */
    @Override
    public E get(int index) {
        //1,校验index的合法性
        pointerIndex(index);
        //2,根据具体位置获取对应的节点数据
        Node<E> node = getNode(index);
        //3,将节点中的元素返回
        return node.item;
    }

    /**
     * 校验所给定的指针是否在链表的有效范围内
     * @param index
     */
    private void pointerIndex(int index){
        // 大于等于0并且小于链表长度
        if (!(index >= 0 && index < this.size)){
            //获取最大的索引指
            int a = this.size-1;
            // 抛出索引越界异常,显示错误信息
            throw new IndexOutOfBoundsException("你输入的指针为:"+index + "最大指针为:"+a);
        }
    }

    /**
     * 根据指针获取节点
     * @return 返回给定索引处的节点
     */
    private Node getNode(int index){
        //从头节点开始遍历链表
        Node<E> node = this.head;
        //移动指针,指向下一个节点,直到所给定的索引位置
        for (int i = 0;i< index;i++){
            node = node.next;
        }
        //返回给定索引处的节点
        return node;
    }

    @Override
    public int size() {
        return this.size;
    }

    @Override
    public E remove(int index) {
        //校验index的合法性
        this.pointerIndex(index);

        //根据index指针找到该节点对象数据
        Node<E> node = this.getNode(index);
        //获取该节点对象中的元素
        E item = node.item;
        //向该节点对象中单向链表删除

        //判断当前删除的节点是否为头节点
        if (this.head == node){
            this.head = node.next;//如果是删除头节点,头节点的下一个节点,赋值给了头节点
        }else {
            Node<E> node1 = this.head;//拿头节点
            for (int i = 0 ; i<index - 1 ; i++){
                node1=node1.next;
            }
            node1.next = node.next;//将节点的下一个节点赋值给该节点
        }
        node.next = null;

        this.size -- ;//删除成功长度减一

        return item;//返回元素
    }

    /**
     * 修改节点数据
     * @param index 挪动指针
     * @return 返回修好的值
     */
    @Override
    public E set(int index,E element) {
        //校验index的合法性
        pointerIndex(index);
        //获取index处的节点
        Node<E> node = getNode(index);
        //将节点值数据进行赋值替换
        return node.item = element;
    }
    /**
     * 使用内部类定义单向链表中的节点对象
     *
     */
    class Node<E>{
        //数据域
        private E item;//存储的数据

        //指针域
        private Node next;//存储下一个节点对象的地址

        //无参构造方法
        public Node(){

        }
        //全参构造方法
        public Node(E item,Node next){
            this.item = item;
            this.next = next;
        }

    }
}

测试
public static void main(String[] args) {
    MyLinkedList myLinkedList = new MyLinkedList();

    myLinkedList.add(12);
    myLinkedList.add(13);
    myLinkedList.add(14);
    myLinkedList.add(15);
    myLinkedList.add(16);
    System.out.println("根据指针找到值"+myLinkedList.get(4));
    System.out.println("删除的节点"+myLinkedList.remove(0));
    System.out.println(myLinkedList);
    System.out.println(myLinkedList.size());
    System.out.println(myLinkedList.set(3,"张三");


    for (int i=0;i<myLinkedList.size(); i++){

        System.out.print(myLinkedList.get(i)+",");
    }

}

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

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

相关文章

零基础玩转C语言—结构体【初阶】

大家好&#xff0c;我是深鱼~ 目录 【前言】&#xff1a; 一、结构体的声明 1.1结构的基本知识 1.2结构的声明 1.3结构体成员的类型 1.4结构体变量的定义和初始化 二、结构体成员的访问 【前言】&#xff1a;本章来介绍结构体的部分知识&#xff0c;并不会深入讲解&…

webstorm格式化代码后单引号转成了双引号

webStorm格式化js代码时单引号变成了双引号&#xff0c;问题如下&#xff1a; 格式化前&#xff1a; 格式化后&#xff1a; 解决办法&#xff1a; window: File -> Settings -> Editor -> Code Style -> Javascript&#xff1b; mac: webStorm -> Preference …

了解回归测试吗?今天给大家详解一下回归测试

测试工作中&#xff0c;新人对于测试流程、测试方法都有可以直接拿来用的教材&#xff0c;但是对于回归测试中的bug处理的细节&#xff0c;往往需要我们更多的经历才能更好的完成自己的工作&#xff0c;下面我们来谈一谈回归测试bug的处理中需要关注的点&#xff1a; 一、什么…

Docker 镜像解密:分层存储与镜像构建原理

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

国内办公协作系统评测:5 款软件推荐

办公协作系统是现代信息化办公的必备工具之一&#xff0c;对于企业来说&#xff0c;选择一款好用的办公协作系统非常重要。然而&#xff0c;在众多的办公协作系统中&#xff0c;哪个好用是一个让人头痛的问题。总体而言&#xff0c;国内的办公协作系统已经相当成熟和完善&#…

基于linux下的高并发服务器开发(第四章)- 多线程实现并发服务器

>>了解文件描述符 文件描述符分为两类&#xff0c;一类是用于监听的&#xff0c;一类是用于通信的&#xff0c;在服务器端既有监听的&#xff0c;又有通信的。而且在服务器端只有一个用于监听的文件描述符&#xff0c;用于通信的文件描述符是有n个。和多少个客户端建立了…

vue 前端一键导出excel文件并附带表格样式

1、安装xlsx、xlsx-style、file-saver三个包 //xlsx与file-saver指定版本安装&#xff0c;解决默认安装utils未定义的问题 npm install --save xlsx0.17.0 npm install --save file-saver2.0.5 npm install xlsx-style --save 2、在使用的页面引入 import XLSX from xlsx //…

对顶堆算法

对顶堆可以动态维护一个序列上的第k大的数&#xff0c;由一个大根堆和一个小根堆组成&#xff0c; 小根堆维护前k大的数(包含第k个)大根堆维护比第k个数小的数 [CSP-J2020] 直播获奖 题目描述 NOI2130 即将举行。为了增加观赏性&#xff0c;CCF 决定逐一评出每个选手的成绩&a…

【暑期每日一练】 day10

目录 选择题 &#xff08;1&#xff09; 解析&#xff1a; &#xff08;2&#xff09; 解析&#xff1a; &#xff08;3&#xff09; 解析&#xff1a; &#xff08;4&#xff09; 解析&#xff1a; &#xff08;5&#xff09; 解析&#xff1a; 编程题 题一 …

Klipper seria.c 文件代码分析

一. 前言 Klipper 底层硬件的串口模块程序写的是否正确是决定下位机与上位机能否正常通信的前提&#xff0c;如果这个文件的驱动没写好&#xff0c;那上位机控制下位机就无从谈起&#xff0c;更无法通过上位机去验证下位机程序的正确性。 本篇博文将详细解析 Klipper src 文件夹…

提词器怎么用?这个方法看一看

提词器怎么用&#xff1f;在现代社会中&#xff0c;提词器的应用场景非常广泛。除了学习、工作、听力障碍和翻译&#xff0c;它还可以应用于其他领域&#xff0c;如演讲、广播、新闻报道等。比如说&#xff0c;在演讲中&#xff0c;提词器可以帮助演讲者更好地掌握演讲内容。演…

网络防御之VPN

配置IKE 第一阶段 [r1]ike proposal 1 [r1-ike-proposal-1]encryption-algorithm aes-cbc-128 [r1-ike-proposal-1]authentication-algorithm sha1 [r1-ike-proposal-1]dh group2 [r1-ike-proposal-1]authentication-method pre-share[r1]ike peer aaa v1 [r1-ike-peer-aaa…

提升数据质量的四大有效方式

在数字时代的今天&#xff0c;企业对于高质量、值得信赖的数据的需求越来越高。 目前&#xff0c;已经有很多企业将数据质量视为技术问题而非业务问题&#xff0c;这也是获取高质量数据的最大限制因素。只有查找技术缺陷&#xff0c;例如重复数据、缺失值、乱序序列&#xff0…

api自动化测试

API测试已成为日常的测试任务之一&#xff0c;为了提高测试效率&#xff0c;减少重复的手工操作&#xff0c;API自动化测试也逐渐变得愈加重要&#xff0c;本文是自己在API自动化测试方面的一些经验积累和心得、汇总成文&#xff0c;以飨读者 我相信自动化技能已经成为高级测试…

uniapp跨域解决

uniapp跨域解决 跨域是什么 跨域指的是浏览器不能执行其他网站的脚本&#xff0c;当一个网页去请求另一个域名的资源时&#xff0c;域名、端口、协议任一不同&#xff0c;就会存在跨域。跨域是由浏览器的同源策略造成的&#xff0c;是浏览器对JavaScript施加的安全限制。 报错…

直线导轨的精密等级以及划分依据

直线导轨的作用&#xff0c;是用来支撑和引导运动部件&#xff0c;按给定的方向做往复直线运动的&#xff0c;直线导轨是高精密度的传动元件&#xff0c;广泛使用在各行各业中。 直线导轨的精密等级是判断产品质量的一个重要指标。在众多种类的直线导轨产品中&#xff0c;精密等…

【BASH】回顾与知识点梳理(一)

【BASH】回顾与知识点梳理 一 前言一. 认识与学习 BASH1.1 硬件、核心与 Shell1.2 为何要学文字接口的 shell&#xff1f;1.3 系统的合法 shell 与 /etc/shells 功能1.4 Bash shell 的功能1.5 查询指令是否为 Bash shell 的内建命令&#xff1a; type1.6 指令的下达与快速编辑按…

vue3搭建Arco design UI框架

技术&#xff1a;Vue3.2.40 UI框架&#xff1a;Arco design 2.44.7 需要安装:yarn 1.22.19 和npm 8.19.4 1.第一步安装本地全局arco脚手架 管理员运行CMD npm i -g arco-cli安装成功后如下&#xff1a; 2.第二步在需要存放项目的文件夹拉取项目 我这里把项目存放在 D:\W…

CTF:信息泄露.(CTFHub靶场环境)

CTF&#xff1a;信息泄露.&#xff08;CTFHub靶场环境&#xff09; “ 信息泄露 ” 是指网站无意间向用户泄露敏感信息&#xff0c;泄露了有关于其他用户的数据&#xff0c;例如&#xff1a;另一个用户名的财务信息&#xff0c;敏感的商业 或 商业数据 &#xff0c;还有一些有…

【枚举+结论】icpc2022 济南 A

Problem - A - Codeforces 题意&#xff1a; 思路&#xff1a; 本来的思路是这样的 考虑最后会变成什么数&#xff0c;手摸了几个发现&#xff0c;都是2&#xff0c;不论本来的集合是不是包含2 然后就是猜测是不是直接变成2就好了 然后要去掉m个&#xff0c;直接考虑去掉最…