从数组与链表到单链表的反转,一文带你吃透

简介: 阿粉发现大家在说链表的时候,就会常说另外一个概念:数组。既然数组和链表,常常会拿到一起做比较。那咱们今天就先来说说数组和链表。

数组与链表

数组最大的一个特点就是,需要一块连续的内存空间。假设现在内存空间剩余了 1MB ,但是它不是连续的,这个时候申请一个大小为 1MB 的数组,会告诉你申请失败,因为这个内存空间不连续。

链表最大的一个特点是,不需要一块连续的内存空间。还是上面那个例子,如果申请的不是大小为 1MB 的数组,而是链表,就会申请成功。

如果只是理解到了这个层面,你是不是会觉得,我以后一直用链表这种数据结构就可以了?不不不,数组也有它自己的优势。

阿粉在查阅相关资料时,发现数组简单易用,又因为它使用的是连续内存空间,就可以借助 CPU 的缓存机制,预读数组中的数据,因而访问效率更高,所以在插入,删除操作比较少,而查询比较多的情况下,使用数组是比较有优势的。

链表在内存中不是连续存储,对 CPU 缓存机制不够友好,也就没办法进行有效预读。所以链表适用于在插入,删除操作比较多的情况下使用。

链表

链表分为单链表,循环链表,和双向链表。

对于单链表来说,它的第一个节点也就是头结点记录着链表的基地址,而最后一个节点也就是尾节点则指向一个空地址 NULL ,循环链表也可以理解成特殊的单链表,只不过尾节点由原来指向一个空地址 NULL 改为了指向头结点。

单链表是这样的:78.jpg

循环链表是这样的:

79.jpg

但是在实际开发中,更加常用的链表结构是:双向链表。

它的结构是这样的:

80.jpg

我们能够看到它的特点是:占用内存较多,支持双向遍历。因为它有两个指针,所以相对单链表,一个数据就会多占用一些内存。

既然它占用内存较多,为什么在实际开发中还比较常用呢,这里面有一个思想在里面,咱们具体来讲讲。

我们知道,单链表,双链表在删除的时候,时间复杂度为 O(1) ,但是在实际开发中它的时间复杂度并不是这样,为什么呢?

这样想,一般在做数据删除的时候,你的操作是怎样的?

首先,查找在节点中「值等于给定某个值」的节点,找到之后再做删除对吧?也就是说在删除之前,是需要做查找这个工作的。而单向链表和双向链表在查找的时候时间复杂度为 O(n) ,因为它为了找到这个要删除的元素,需要将所有的元素都遍历一遍。将上面过程梳理一下就是,查找时间复杂度为 O(n) ,删除时间复杂度为 O(1) ,总的时间复杂度为 O(n) 。

以上过程在双链表中是怎样的呢?因为双链表支持双向遍历,所以查找这个操作对它来说时间复杂度为 O(1) ,因为它是双向遍历,所以在查找元素时,不需要将所有的元素进行遍历,删除时时间复杂度为 O(1) ,总的时间复杂度为 O(1) 。

因为双向链表的时间复杂度为 O(1) ,所以在开发中它是比较受欢迎的。而在这其中体现的一个最重要的思想就是:空间换时间。

当内存空间相对时间来说不是那么重要的话,那我们是不是就可以忽略次要的因素,着重解决主要矛盾?

光说不做不符合阿粉的风格啊。阿粉今天实现了一个比较常见的单链表操作---单链表反转

单链表反转代码实现

/**
 * 链表反转
 */
publicclass ReverseList {
    publicstaticclass Node{
        privateint data;
        private Node next;
        public Node(int data , Node next){
            this.data=data;
            this.next=next;
        }
        public int getData(){
            return data;
        }
    }
    public static void main(String[] args){
        // 初始化单链表
        Node node5=new Node(5,null);
        Node node4=new Node(4,node5);
        Node node3=new Node(3,node4);
        Node node2=new Node(2,node3);
        Node node1=new Node(1,node2);
        // 调用反转方法
        Node reverse=reverse(node1);
        System.out.println(reverse);
    }
    /**
     *单链表反转
     * @param list 为传入的单链表
     */
    public static Node reverse(Node list){
        Node current=list, // 定义 current 为当前链表
                afterReverse=null;   // 定义 afterReverse 为转换之后的新链表,初始为 null
        // 当前链表不为空,进行反转操作
        while (current!=null){
            // 1. 保存当前节点的 next 指针指向的链表
            Node next=current.next;
            // 2. 将当前节点的 next 指针指向反转之后的新链表
            current.next=afterReverse;
            // 3. 保存当前的链表状态到新链表中
            afterReverse=current;
            // 4. 将当前节点指针后移一位,进行下一次循环
            current=next;
        }
        return afterReverse;
    }
}

接下来咱们断点调试,看看每次结果:

初始状态:

81.jpg

第一次循环结束

82.jpg

第二次循环结束

83.jpg

第三次循环结束

84.jpg

第四次循环结束

85.jpg

第五次循环结束

86.jpg

在写这篇文章的时候,特别是单链表反转那一块,考虑了很久,借鉴网上思路做出来,有的思路真的是很巧妙。

在阿粉的一步步断点调试 + 手写代码下,终于拿下了单链表反转。你掌握了嘛?

参考

  • 《极客时间》算法面试通关40讲
相关文章
|
存储 索引
数据结构单链表之反转链表 | 第九套
数据结构单链表之反转链表 | 第九套
295 0
|
前端开发 JavaScript
HTML 转 Markdown 如此简单
本文推荐 HTML 转为 markdown 的工具和实现方式,并找到了一个快捷技巧,收藏等于学会。
2458 1
|
内存技术 程序员 异构计算
带你读《基于CUDA的GPU并行程序开发指南》之三:改进第一个CPU并行程序
本书旨在帮助读者了解与基于CUDA的并行编程技术有关的基本概念,并掌握实用c语言进行GPU高性能编程的相关技巧。本书第一部分通过CPU多线程编程解释了并行计算,使得没有太多并行计算基础的读者也能毫无阻碍地进入CUDA天地;第二部分重点介绍了基于CUDA的GPU大规模并行程序的开发与实现,并通过大量的性能分析帮助读者理解如何开发一个好的GPU并行程序以及GPU架构对程序性能的影响;本书的第三部分介绍了一些常用的CUDA库。
|
自然语言处理 索引
RAG入门:理解检索增强生成模型的基本原理
【10月更文挑战第21天】作为一名长期从事自然语言处理(NLP)研究的技术人员,我一直在关注各种新兴技术的发展趋势。其中,检索增强生成(Retrieval-Augmented Generation, RAG)模型引起了我的特别兴趣。RAG技术结合了检索系统和生成模型的优点,旨在解决传统生成模型在处理长文本理解和生成时所面临的挑战。本文将从个人的角度出发,介绍RAG的基本概念、工作原理及其相对于传统生成模型的优势,并探讨一些基本的实现方法。
1411 1
|
存储 弹性计算 Linux
在linux docker容器中挂载使用云存储网关
本文介绍在linux环境下的docker容器中如何通过云存储网关以文件接口存储访问对象存储(OSS)中的数据。
3030 1
在linux docker容器中挂载使用云存储网关
|
8月前
|
Linux BI
rpm打包实战之Rocky Linux 9下打包protobuff
本教程介绍在Rocky Linux下使用RPM打包Protobuf的完整流程,涵盖rpmdevtools环境搭建、SPEC文件编写、rpmbuild构建及rpmlint规范检查,实现软件包的标准化制作与质量管控。
|
存储 程序员 编译器
STM32的内存管理相关(内存架构,内存管理,map文件分析)
STM32 的内存架构,内存管理以及 map 文件分析
814 0
STM32的内存管理相关(内存架构,内存管理,map文件分析)
|
5月前
|
存储 人工智能 自然语言处理
JBoltAI识图阅卷解析:手写答题卡智能阅卷的技术实践
JBoltAI识图阅卷方案融合NLP与图像识别,自动提取手写答题卡题号及答案,生成结构化数据,提升阅卷效率、降低人工误差。适用于学校、考试机构等大规模场景,亦为Java开发者提供AI落地实践范例。(239字)
318 0
|
5月前
|
存储 弹性计算 固态存储
保姆级!阿里云服务器 CPU 内存配置详细指南,新手直接抄
阿里云服务器配置指南:新手必看!个人开发者推荐轻量应用服务器或ECS经济型e实例(2核2G/99元起);企业用户首选u1、c7、g7等独享型实例。详解CPU/内存、带宽(建议5M性价比最高)、系统盘(ESSD更优)选择逻辑,助你精准匹配业务需求。(239字)
688 2
|
7月前
|
机器学习/深度学习 算法 小程序
从 GAN 到 Diffusion:移动端图像去水印算法的“算力突围”实战解析
深度解析图像修复(Image Inpainting)技术的演进。探讨如何在微信小程序 2MB 包体积限制下,利用 Serverless 架构实现快速去水印推理。“香蕉一键去水印”的技术架构案例分析。

热门文章

最新文章