反转链表(java)

        在做力扣题的时候,看着答案都不懂怎么来的。小白到哪种程度呢,我实在不知道答案代码中的head传过来的到底是一个数还是一串数。在搜索后终于搞懂了这道题。

1.首先我们要明白什么是链表。

单向链表介绍
        链表是一种数据结构,和数组同级。比如,Java中我们使用的ArrayList,实现原理是数组。而LinkedList的实现原理就是链表。在链表中,数据的添加和删除都较为方便,就是在进行循环遍历时效率不高,访问比较耗费时间。
        单向链表是一种线性表,实际上是由节点(Node)组成的,一个链表拥有不定数量的节点。其数据在内存中存储是不连续的,它存储的数据分散在内存中,每个结点只能也只有它能知道下一个结点的存储位置。由N各节点(Node)组成单向链表,每一个Node记录本Node的数据及下一个Node。向外暴露的只有一个头节点(Head),我们对链表的所有操作,都是直接或者间接地通过其头节点来进行的。(这道题中,只要明白单链表就可以了,所以没有深究)

        上图中最左边的节点即为头结点(Head),但是添加节点的顺序是从右向左的,也就是尾插。最先添加的节点(Head)对下一节点的引用可以为空。引用是引用下一个节点的地址而非下一个节点的对象。因为有着不断的引用,所以头节点就可以操作所有节点了。
下图描述了单向链表存储情况。存储是分散的,每一个节点只要记录下一节点,就把所有数据串了起来,形成了一个单向链表。

        节点(Node)是由一个需要储存的对象(val或者data)及对下一个节点的引用(Node.next)组成的。也就是说,节点拥有两个成员:储存的对象、对下一个节点的引用。下面图是具体的说明:

以上内容来自:Java链表ListNode的理解与操作技巧 - 知乎

2.head传递的含义

        看了上面的介绍,我们对单向链表有了一定的认识,知道了对象的组成与指代。接下来我们来了解一下“head”到底传过来的是什么。

是由头指针唯一确定,因此单链表可以用头指针的名字来确定

如何表示空表

情况一:无头结点时,头指针为空表示空表
情况二:有头结点时,当头结点的指针域为空时表示空表

头节点介绍来自:单链表(基础)_链表头结点是空的吗-CSDN博客

这一段很清晰的说明了head是什么,怎么来,怎么去。

3.图解代码分析

        接下来我们就进入代码,一句一句分析,链表是如何变化的。我们用上文赵钱孙李周的例子。

图解链表反转代码的实现

        接下来,我们图解以上代码实现,先对以上实现代码加上行号,在力扣题解中,简化了定义的步骤,默认链表已经定义好。此代码只是反转,返回部分。如下:

public ListNode reverseList(ListNode head) { //1
ListNode prev = null;  // 2
ListNode curr = head;  // 3
while (curr != null) {  //4
    ListNode nextTemp = curr.next; //5
    curr.next = prev;  // 6
    prev = curr;  //7
    curr = nextTemp; //8
}
return prev;  //9
}

3.1第一行代码图解

public ListNode reverseList(ListNode head) { //1

        我们顺着题目描述意思,假设链表就有1、2、3个元素吧,后面还跟着一个null,又因为输入是ListNode head,所以这个即将要反转的链表如下:

3.2第二行代码图解

ListNode prev = null; // 2

        将null赋值给prev,即prev指向null,可得图如下:

3.3第三行代码图解

ListNode curr = head;

将链表head赋值给curr,即curr指向head链表,可得图如下:

循环部分代码图解

while (curr != null) { //4

ListNode nextTemp = curr.next; //5

curr.next = prev;  // 6

prev = curr;  //7

curr = nextTemp; //8

}

循环部分是链表反转的核心部分,我们先走一遍循环,图解分析一波。

3.4 因为curr指向了head,head不为null,所以进入循环。先来看第5行:

ListNode next = curr.next; //5

        把curr.next 赋值给next变量,即next指向curr的下一节点(即节点2),这里有一点,next知识一个变量名,与curr.next中的next没关系。写成ListNode next1 = curr.next;一样了、可以运行。因为是缝合的他人的资料,所以在部分变量有些不同,nextTemp也就是代码中定义的next。可得图如下:

                

curr.next = prev;  // 6

把prev赋值给curr.next,因为prev初始化化指向null,即curr(节点1)指向了null,链表图解成这样了:

3.5然后我们看执行到第7行

prev = curr;  //7

把curr赋值给prev,prev指向curr,图解如下:

3.6 接着,我们执行到第8行:

curr = nextTemp; //8
把nextTemp赋值给curr,即curr指向nextTemp,图解如下:

                                                                 

                              

至此,第一遍循环执行结束啦,回到循环条件,curr依旧不为null,我们继续图解完它。

5-8行代码又执行一遍,依次可得图:

ListNode nextTemp = curr.next; //5
curr.next = prev; // 6
prev = curr; //7
curr = nextTemp; //8

3.7 执行完ListNode nextTemp = curr.next;后:

                                                                                                      

                           

3.8 执行完curr.next = prev;

        这一步是关键,第一次循环指向空,不易看出来,这个时候,curr已经变成第二个数(例子里面就是存储地址为0007,数值为钱,指向节点为0013),在运行这句代码后,指向节点0013,就变成了指向prev(0031)<赵的存储地址>。这就实现了反转,最最开始是,赵钱,现在变成了钱赵

图解如下:

3.9 执行完prev = curr;后:

                                                                             

310 执行完curr = nextTemp;后:

                                                                                                       

                                                                            

这一段来自:转载:看一遍就理解,图解单链表反转_反转链表难理解_kevin--你不知道的事的博客-CSDN博客

        至此,第二次循环结束,后面的3啊,4啊啥的都是一样的步骤,懒得写了,就不加赘述,我在改代码学习是,就是不明白他们的值到底是怎么传递的。甚至想过prev是不是生成一个新的链表,像数组一样,一个数一个数的加上去。但总感觉指向不对,现在看来更像将链表一个拆下来,组装,再拆下一个,再组装。头文件在搜索后才明白。最后就是2到1指向那一步,这一步想清楚的那一刻,真正有豁然开朗的感觉。

此文章是在学习查询理解的历程,是各个文章的缝合,若有侵权,联系删除!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值