【数据结构】单向链表的原理及实现

news2024/10/6 20:39:04

1.什么是单链表

链表里的数据是以节点的方式表示的,每一个结点的组成是由:元素+指针来组成的,元素就是存储数据里的存储单元,指针就是用来连接每一个结点的地址数据。这个以结点的序列来表示线性表被称作为单链表。

单链表是一种链式储存结构。在物理储存单元不连续,非顺序。

  • 结点里的数据域是用来存储数据元素的
  • 指针是用于指向下一个具有相同结构的结点
  • 因为只有一个指针结点,故而被称为单链表

在这里插入图片描述

2.单链表的实现

末尾增加元素void add(T data)
指定下标增加元素void add(int index,T data)
删除指定下标元素void delete(int index)
获取指定下标的元素T get(int index)
修改指定下标的元素void update(int index,T data)
遍历输出所有元素void show()
获取链表的长度int length()

(1)定义数据节点实体

在这里插入图片描述

(2)向链表末尾增加元素

在这里插入图片描述

(3)指定下标向链表增加元素

在这里插入图片描述

(4)删除指定下标元素的数据

在这里插入图片描述

(5)修改指定下标的元素

在这里插入图片描述

(6)获取指定下表的元素

在这里插入图片描述

(7)循环遍历输出

在这里插入图片描述

(8)获取当前有效的元素个数

在这里插入图片描述

3.单链表测试

(1)整体代码实现

public class SingleLinkedList<T> {

    /**
     * 定义头节点
     */
    public Node<T> head = new Node<>(null);

    /**
     * 链表有效元素个数
     */
    private int length=0;

    /**
     * 向单链表中添加一个元素
     * @param data
     */
    public void add(T data){
        //定义当前数据
        Node<T> nodeData = new Node<>(data);
        //定义辅助指针
        Node<T> cur = head;
        //while 循环不断遍历找到最后一个节点
        while (cur.next != null) {
            //只要有下一个节点,辅助指针就向下移动一位
            cur = cur.next;
        }
        //while循环之后,cur已经是最后一个节点,将data赋值到cur的下一个节点上
        cur.next = nodeData;
        //整体链表长度++
        length++;
    }

    /**
     * 向单链表中添加一个元素
     * @param data
     */
    public void add(int index,T data){
        //判断index是否合法
        if(index <0 || index >length){
            System.out.println("index不合法");
            return;
        }
        //定义当前数据
        Node<T> nodeData = new Node<>(data);
        //定义辅助指针
        Node<T> cur = head;
        //找到当前index的元素
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        //将当前节点的next设置成cur的next
        nodeData.next = cur.next;
        //将cur.next设置成nodeData(当前节点)
        cur.next = nodeData;
        //整体链表长度++
        length++;
    }

    /**
     * 遍历输出链表中全部节点
     */
    public void show(){
        //定义辅助指针
        Node<T> cur = head;
        //判断链表中是否存在元素
        if (cur.next == null){
            System.out.println("当前单向链表中元素为空");
            return;
        }
        while (cur.next != null){
            System.out.print(cur.next.data+" ");
            cur = cur.next;
        }
        System.out.print("\n");
    }

    /**
     * 修改指定下标的数据
     * @param index
     * @param data
     */
    public void update(int index,T data){
        Node<T> cur = head;
        if(index > length){
            System.out.println("当前index查过边界");
            return;
        }
        //遍历寻找指定index的节点
        for (int i = 0; i <= index; i++) {
            cur = cur.next;
        }
        //找到之后将新的data赋值上去
        cur.data = data;
    }

    /**
     * 删除指定下标元素
     * @param data
     */
    public void delete(int index){
        Node<T> cur = head;
        if(index > length){
            System.out.println("当前index超过边界");
            return;
        }
        //遍历寻找指定index的节点
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        //找到之后将新的data赋值上去,将后一个data赋值到当前节点上
        cur.data = cur.next.data;
        //将当前节点的next变成当前节点的next.next相当于将当前元素的next节点删掉
        cur.next = cur.next.next;
        //单链表整体有效元素减一
        length--;
    }

    /**
     * 获取指定下标元素的数据
     * @param index
     * @return
     */
    public T get(int index){
        //校验参数是否合法
        if(index<0 || index>length){
            System.out.println("当前index超过边界");
        }
        //定义辅助节点
        Node<T> cur = head;
        //找到对应下标的node
        for (int i = 0; i <=index; i++) {
            cur = cur.next;
        }
        //返回node.data
        return cur.data;
    }

    /**
     * 获取单链表的长度
     * @return
     */
    public int length(){
        return this.length;
    }

    /**
     * 内部节点类
     * @param <T>
     */
    class Node<T>{

        /**
         * 定义数据
         */
        public T data;

        /**
         * 定义下一个节点的
         */
        public Node<T> next;

        public Node(T data) {
            this.data = data;
        }
    }
}

(2)测试代码

public class Main {
    public static void main(String[] args) {
        SingleLinkedList<Integer> singleLink = new SingleLinkedList<>();

        //增加元素
        singleLink.add(1);
        singleLink.add(2);
        singleLink.add(3);
        System.out.print("新增之后:");
        singleLink.show();

        //删除元素
        singleLink.delete(0);
        System.out.print("删除index为0之后:");
        singleLink.show();

        //修改元素
        singleLink.update(0,9);
        System.out.print("修改index为0之后:");
        singleLink.show();

        //获取单链表的长度
        int length = singleLink.length();
        System.out.println("单链表的长度:"+length);

        //获取指定下标的数据
        System.out.println("获取指定下标的数据:"+singleLink.get(1));

        //指定下标插入数据
        singleLink.add(1,6);
        System.out.print("在index为1位置插入数据之后:");
        singleLink.show();
    }
}

在这里插入图片描述

4.链表的优缺点

  • 优点:

    • 链表的内存空间不连续。

    • 如果知道要处理节点的前一个位置,则进行插入和删除的复杂度为O(1);

    • 如果不知道要处理节点的前一个位置,则进行插入和删除的复杂度为O(N)。

    • 头插、头删的效率高,时间复杂度是O(1)。

    • 没有空间限制,不会溢出,可以存储很多元素。

  • 缺点:

    • 链表不支持随机访问,查找元素效率低,需要遍历节点,时间复杂度是O(n)。

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

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

相关文章

牛客寒假算法集训营1 补题

标题迷惑大赏 A、World Final? World Cup! 题目描述 众所周知&#xff0c;2022年是四年一度的世界杯年&#xff0c;那么当然要整点足球题。本题需要你模拟一次点球大战。 假设对战双方为A和B&#xff0c;则点球大战中双方会按照ABABABABAB方式来罚点球&#xff0c;即两队交…

【闪电侠学netty】第7章 数据载体ByteBuf的介绍

1. 内容概要 1.1 总结 1.1.1 内存管理 Netty 使用的是堆外内存&#xff0c;需要手动释放&#xff0c;使用引用计数的方式管理内存&#xff0c;当引用计数 0&#xff0c;回收ByteBuf 底层内存 原则&#xff1a;谁使用retain() , 谁释放release() 1.1.2 创建ByteBuf的方式 B…

ASCII码,字符,字符串三者之间的关系

程序调试中遇到问题&#xff1a;在使用sprintf 函数&#xff0c;在转换字符串时&#xff0c;如果遇到0时&#xff0c;会自动认为是结束标志&#xff0c;0以后的内容不会被添加进来。复习一下字符串&#xff1a;一. ASCII码是什么&#xff1f;ASCII 全称为 ( American Standard …

【2023更新】通过硬件触发信号实现OAK多相机之间的同步拍摄

编辑&#xff1a;OAK中国 首发&#xff1a;oakchina.cn 喜欢的话&#xff0c;请多多&#x1f44d;⭐️✍ 内容可能会不定期更新&#xff0c;官网内容都是最新的&#xff0c;请查看首发地址链接。 ▌前言 Hello&#xff0c;大家好&#xff0c;这里是OAK中国&#xff0c;我是助手…

经典文献阅读之--NeRF-SLAM(单目稠密重建)

0. 简介 最近几年随着深度学习的发展&#xff0c;现在通过深度学习去预估出景深的做法已经日渐成熟&#xff0c;所以随之而来的是本文的出现《Real-Time Dense Monocular SLAM with Neural Radiance Fields》。这篇文章是一个结合单目稠密SLAM和层次化体素神经辐射场的3D场景重…

【自学Docker 】Docker管理命令大全(下)

文章目录Docker kill命令Docker kill命令概述Docker kill命令语法Docker kill命令参数案例使用容器 ID 杀掉容器使用容器名杀掉容器Docker kill命令总结Docker rm命令Docker rm命令概述Docker rm命令语法Docker rm命令参数案例删除已停止的容器删除正在运行的容器Docker rm命令…

13.拷贝控制

文章目录拷贝控制13.1拷贝、赋值与销毁13.1.1拷贝构造函数合成拷贝构造函数拷贝初始化参数和返回值编译器可以绕过拷贝构造函数13.1.2拷贝赋值运算符重载赋值运算符合成拷贝赋值运算符13.1.3析构函数析构函数完成什么工作什么时候会调用析构函数合成析构函数13.1.4三/五法则需要…

寒假题练——day(4)

题目 1 一个数组中只有两个数字是出现一次&#xff0c;其他所有数字都出现了两次。 编写一个函数找出这两个只出现一次的数字。 #include<stdio.h> int main() {int arr[] { 1, 3, 8, 1, 3, 8, 4, 6 };int num 0;int sz sizeof(arr) / sizeof(arr[0]);int i 0;int…

【Linux】六、Linux 基础IO(二)|重定向|如何理解 Linux一切皆文件|缓冲区

目录 五、重定向 5.1 什么是重定向 5.2 系统调用 dup2 5.3 三种重定向测试 5.3.1 输出重定向(>) 5.3.2 追加重定向(>>) 5.3.3 输入重定向(<) 5.4 父子进程拷贝问题 六、如何理解 Linux一切皆文件 七、缓冲区 7.1 认识缓冲区 7.2 缓冲区的刷新策略 …

连续系统PID的Simulink仿真-2

仍以二阶线性传递函数为被控对象&#xff0c;进行模拟PID 控制。被控对象形式为,其中b为在[103,163]范围内随机变化&#xff0c;a为在[15,35]范围内随机变化&#xff0c;则被控对象的描述方式可转换为&#xff1a;S函数是Simulink一项重要的功能&#xff0c;采用S函数可实现在S…

Pandas 数据清洗

Pandas 数据清洗数据清洗是对一些没有用的数据进行处理的过程。很多数据集存在数据缺失、数据格式错误、错误数据或重复数据的情况&#xff0c;如果要对使数据分析更加准确&#xff0c;就需要对这些没有用的数据进行处理。在这个教程中&#xff0c;我们将利用 Pandas包来进行数…

微软ATP带你看| 爆火的ChatGPT是什么?

&#xff08;本文阅读时间&#xff1a;7分钟&#xff09;OpenAI最新聊天机器人ChatGPT火爆全网&#xff01;能写代码、编剧本&#xff0c;马斯克都盛赞它“好得吓人”&#xff01;ChatGPT是什么GPT(Generative Pre-trained Transformer)系列是由OpenAI提出的非常强大的预训练语…

MaxCompute SQL示例解析

MaxCompute SQL示例解析 介绍MaxCompute SQL常见使用场景&#xff0c;掌握SQL的写法。 准备数据集 本文以emp表和dept表为示例数据集。您可以自行在MaxCompute项目上创建表并上传数据。 emp.csv中数据如下 7369,SMITH,CLERK,7902,1980-12-17 00:00:00,800,20 7499,ALLEN,SALES…

aws codebuild 使用和配置codebuild测试报告

参考资料 使用 Amazon CodeBuild 中的测试报告在 CodeBuild 使用AWS CLI样本中创建测试报告aws-codebuild-samples 在codebuild构建过程中获取有关在构建期间运行的测试的详细信息。 codebuild测试报告 通过在buildspec.yaml中配置报告组&#xff0c;运行构建项目时系统将运…

【代码随想录】96.不同的二叉搜索树

96.不同的二叉搜索树 思路 n为1的时候有一棵树&#xff0c;n为2有两棵树&#xff0c;这个是很直观的。 n为3的时候&#xff0c;有哪几种情况。 当1为头结点的时候&#xff0c;其右子树有两个节点&#xff0c;看这两个节点的布局&#xff0c;是不是和 n 为2的时候两棵树的布…

控价公司可以帮我们做什么?什么时候需要找第三方控价公司?

如果&#xff0c;我们品牌的销售渠道遭遇了低价乱价、窜货、侵权、假冒等问题&#xff0c;扰乱了我们品牌的渠道秩序&#xff0c;或者是我们在品牌发展的过程中&#xff0c;想通过对行业和竞品的了解来明确发展方向和策略&#xff0c;而自己又分身乏术或无从下手&#xff0c;这…

车辆信息查询

要想查一辆汽车的信息&#xff0c;除了去各个汽车平台上查询&#xff0c;比如汽车之家、易车网、懂车帝等&#xff0c;还可以使用“汽车公告查询”。 通过常规网页百度搜索引擎&#xff0c;输入关键字“汽车公告查询”&#xff0c;就会获取到相关搜索结果&#xff0c;汽车公告查…

C进阶_内存库函数

目录 memcpy 模拟实现memcpy memmove 模拟实现memmove memcmp memcpy 它的函数原型为&#xff1a; void * memcpy ( void * destination, const void * source, size_t num ); 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。 这个函数…

104、【树与二叉树】leetcode ——98. 验证二叉搜索树:递归法[先序+中序+后序]+迭代法(C++版本)

题目描述 原题链接&#xff1a;98. 验证二叉搜索树 解题思路 BST的特点是&#xff1a;当前结点的值&#xff0c;比左子树中的全部结点都大&#xff0c;比右子树中全部结点都小。在代码实现中&#xff0c;要注意不要对比的是某一结点和某一侧的全部值之间的关系&#xff0c;不…

【论文阅读】CenterNet

论文题目&#xff1a;Objects as Points&#xff08;CVPR2019&#xff09; 论文地址&#xff1a;https://arxiv.org/pdf/1904.07850.pdf 发布时间&#xff1a;2019.4.16 机构&#xff1a;UT Austin&#xff0c;UC Berkeley 代码&#xff1a;https://github.com/xingyizhou/…