人物:
两个人,我,小铮.
我 : 今天,我来讲解如何反转链表.
> class Solution {
> public ListNode reverseList(ListNode head) {
> //申请节点,pre和 cur,pre指向null
> ListNode pre = null;
> ListNode cur = head;
> ListNode tmp = null;
> while(cur!=null) {
> //记录当前节点的下一个节点
> tmp = cur.next;
> //然后将当前节点指向pre
> cur.next = pre;
> //pre和cur节点都前进一位
> pre = cur;
> cur = tmp;
> }
> return pre;
> }
> }
还是需要一个临时节点的,然后判断当前不为空,然后就无限循环,循环什么呢?
是的,当前节点先拍张照,然后把当前的节点中,(一个节点有两块,前一个,当前)或(当前,下一个) ,你可能会疑问为什么不是3个,第三个是内容值吧(内容值就是当前?).
这是我猜测的,根据历史和代码猜测. 为什么要拍照当前的下一个?,一个一个向前移动,加一个临时的东西,是最容易操作的,而且直接效率高.
是不是感觉和冒泡的交换差不多,是的,就是交换下一个这种操作. 问题是:这是向前移动还是向后移动.宏观上不好判断是前移还是后移.
大体上看,把下一个给了现在的.就是 前移.
还有初始化没有说.等会说. 卧槽,忘记说目的了.
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
总结来说.题目反转,可以不反转打印前一个吗,不行,所以反转.
-
需要一个临时节点的
-
链表结构 -->[当前值,下一个地址]
-
初始化.
- 需要在方法里建立3个节点,pre意思是前一个:设置为null,多设节点好方便操作和理解,说不定还是必须的
- 第二个代表当前cur,是要操作的节点的head,不是null
- 第三个是pre,意思是前一个,这个不是循环链表也需要前一个,代表一个意思,用来操作
-
判断当前不为空,然后就无限循环
-
循环的内容是:
-
当前节点的下一个节点整体(是节点)先拍张照,拍照留存给临时.
-
对于当前节点的下一个(head的下一个)就像这样[当前值,下一个地址],把pre粘上去,意思就是pre(当前的前一个的内存地址)(样子是引用,就像ListNode pre这样),这个操作的作用是什么呢?
为什么要把pre==null,给下一个呢?因为pre是最后要返回的,不弄一个这个东西,后面不好返回,下一步要给pre这个东西上东西.
-
上东西.把当前对象(节点地址)给pre,这就是把地址前移.方法最后返回的就是pre,就是原来的地址呀.
-
最后就是点题了,就是操作第一步的temp,拍照肯定是要用的.临时给当前. 什么意思呢? 临时是当前的下一个,给当前,就是最简单的移动. 是不是对当前感到疑惑? 那个是当前. —>在这一个循环中,当前就是head.永远不变,最后返回的是pre.
-
看这个动图是不是超级疑惑,我也是.等会解释.
上面的流程还是有点混乱,我再解释一下. 过程很简单 3个z.都是连接的操作的. 循环完,第一个就删除了,4变成第1个.
开始的赋值,两个null,是有用的.只有第一次循环是null,后面都不是,这个要注意了.
其实要想成3条两座小船 [a1,a2] [b1,b2] [c1,c2] . b1是内容,b指b的地址,就是整体 . c的地址==b2.
现在b是head.
可以说c==b2. (所以说,每一个值都与三个有关联 a.a2=b —> b.b2=c )
tmp = cur.next; 第一步,c 拍照 .拍照,偷拍下一个,放入手机,拍照是拍照的当前这个船的尾巴.
第一步 null(手机)=b2 .
cur.next = pre; 第二步,b2放pre(前一个),就是当前的前一个a, 如果最开始就放null,否则就是把第一个删除了后.原来的第一个.头的前面是nulll,所以a1,a2是null.
如果到了第二个循环,a2==b就是pre.因为第一次的第三步,cur给了pre.
第二步总结说就是 : 被拍照的人 换位为 排队的前一个人. 被拍照的人呢?在相机里呢. 结束当前节点,斩断.就像香肠一样,从案板上一刀之后,消失了,到你的独自里面了. 然后有一个线连接. 因为a是空的,所以,现在是a,b都被斩断了. 一轮循环完成,就是一刀斩断. (pre== null == a == a的地址) --> 第二步就是 b2=a
重新总结: 第二步: 把一刀斩断的东西,用线连接给当前的香肠. 更为简单的就是
扔锚.
pre = cur; 就是 a=b. 第一次为什么操作两个节点呢?null,a不算节点,不a算节点. 每一次循环要操作3个节点.
每个循环主要是操作前两个节点,就是当前和前一个,这也是为什么叫 前移 了.第三步,总结
空间转换 简单说: 问题复杂的原因就是.next是一个节点.a.next=b=a2.这样说就容易乱.b给a让人很难理解,b的地址给了pre,a不是pre,pre代表的是前.(前,中,后)不永远代表某一个值,它像一个游泳池,固定就有三个游泳池.船abc,也是呀,只能代表3个状态,以前,现在,未来. 不能代表一长链子的某3个.如果当做具体的3个东西,就很容易混乱.
b的船给了a, 换船. 如果是第一步,a的船呢?第一步,a就没有船,a的船被吃了.
b的船给a, b船上的人呢?b1,b2,a1,a2 哪里去了呢? 这一步意思是, b的船给了a,a第一次是null当然是从宇宙消失了.这一步之后, pre—这个节点永远的有了数值.不在是虚幻的了.
我们很容易把下一次的循环和第一次联系起来,如果使用换船来比喻,应该是把a的人和船换为b的位置,所以不能使用换船理解.
b成为了新的 ‘前一个节点’.所以:
第三步: b船的人全部到了a船,现在成为了以前,中间游泳池的人到了前面的游泳池. 已经算换位置了.现在看,第二步就已经开始换人了,一切居然悄无声息的进行了这么多,你还没有意识到. 第二步. 已经把 前船的位置(或者说整体压缩)给了船里的b2,第三步,中船给前船,直接移动就好了,没有过多的想法,然后第四步,后船给中船.后后船给后船是什么时候的操作呢?
cur.next.next是什么呢? 就是 temp.next . 问题是,什么时候,temp.next 给值? 这不就是下一个循环的开始嘛. 一次处理的是三个节点,不是4个.3.next-----不操作.
第一步的拍照缓存技术.
cur = tmp;
按理说只要两个就可以了呀,当前下一个(地址).不需要知道上一个的地址.知道上一个是不是就是双向链表? 对的.
小铮 : 小哥哥真厉害.
后续更新:
反转链表你能回忆出来吗?
node pre =null
node cur= a
node t= null
while(cur!=null){
//两个z 正z还是反z 忘记了
t=cur.next //拍照 临时最后使用? 是的
// cur.next = pre; //忘记了,解释原因
pre=cur
// cur= t //忘记了,解释原因
}
return pre
cur.next = pre
移位: 你以前一直想的是,cur.next,被切除了,所有不能操作. 其实不是呀,前移.为什么拍照? 因为这个位置要换新东西呀. 拍照的备份,是的,cur.next 是有用的. 最前面的一节是没用的.因为是从 第一次
开始,你总考虑 第一个空节点. 就是很简单呀, 当前要作为 下一次的 前一个(pre) ,所以,幻想一下,如果cur 变为next
要做什么?
java模拟 xxx.next -----是一个真实的东西(节点). 第3 4 都是 整体切换----------- 1-4
都是整体切换? 不存在其他? 加了一个前缀?
之前的 理解有一部分错了.
反转,没有前移,后移. 是改变逻辑关系的.
如图: 改变了箭头方向
输入: 1->2->3->4->5->NULL
输出: NULL<-1<-2<-3<-4<-5
等价: 5->4->3->2->1->NULL
忘记怎么 扔锚了. [a,a1] [b, b1 ] [c,c1 ]
pre当做现在的cur.
步骤简介:
- 拍照
- 循环指向
- 整体交换
- 照片给cur