文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-12-24 19:42

关注

[[314217]]

 

阿粉发现大家在说链表的时候,就会常说另外一个概念:数组。

既然数组和链表,常常会拿到一起做比较。那咱们今天就先来说说数组和链表。

数组与链表

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

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

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

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

链表

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

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

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

单链表是这样的:

 

 

 

 

循环链表是这样的:

 

 

 

 

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

它的结构是这样的:

 

 

 

 

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

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

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

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

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

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

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

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

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

单链表反转代码实现

 

  1.  
  2. public class ReverseList { 
  3.     public static class Node{ 
  4.         private int data; 
  5.         private Node next
  6.  
  7.         public Node(int data , Node next){ 
  8.             this.data=data; 
  9.             this.next=next
  10.         } 
  11.         public int getData(){ 
  12.             return data; 
  13.         } 
  14.     } 
  15.      
  16.     public static void main(String[] args){ 
  17.         // 初始化单链表 
  18.         Node node5=new Node(5,null); 
  19.         Node node4=new Node(4,node5); 
  20.         Node node3=new Node(3,node4); 
  21.         Node node2=new Node(2,node3); 
  22.         Node node1=new Node(1,node2); 
  23.         // 调用反转方法 
  24.         Node reverse=reverse(node1); 
  25.         System.out.println(reverse); 
  26.     } 
  27.      
  28.      
  29.     public static Node reverse(Node list){ 
  30.         Node current=list, // 定义 current 为当前链表 
  31.                 afterReverse=null;   // 定义 afterReverse 为转换之后的新链表,初始为 null 
  32.         // 当前链表不为空,进行反转操作 
  33.         while (current!=null){ 
  34.             // 1. 保存当前节点的 next 指针指向的链表 
  35.             Node next=current.next
  36.             // 2. 将当前节点的 next 指针指向反转之后的新链表 
  37.             current.next=afterReverse; 
  38.             // 3. 保存当前的链表状态到新链表中 
  39.             afterReverse=current
  40.             // 4. 将当前节点指针后移一位,进行下一次循环 
  41.             current=next
  42.         } 
  43.         return afterReverse; 
  44.     } 

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

初始状态:

 

 

 

 

第一次循环结束

 

 

 

 

第二次循环结束

 

 

 

 

第三次循环结束

 

 

 

第四次循环结束

 

 

 

 

第五次循环结束

 

 

 

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

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

参考《极客时间》算法面试通关40讲

来源:Java极客技术内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯