如何链表反转
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何链表反转相关的知识,希望对你有一定的参考价值。
链表反转单向链表的反转是一个经常被问到的一个面试题,也是一个非常基础的问题。比如一个链表是这样的: 1->2->3->4->5 通过反转后成为5->4->3->2->1。最容易想到的方法遍历一遍链表,利用一个辅助指针,存储遍历过程中当前指针指向的下一个元素,然后将当前节点元素的指针反转后,利用已经存储的指针往后面继续遍历。源代码如下:
struct linka
int data;
linka* next;
;
void reverse(linka*& head)
if(head ==NULL)
return;
linka*pre, *cur, *ne;
pre=head;
cur=head->next;
while(cur)
ne = cur->next;
cur->next = pre;
pre = cur;
cur = ne;
head->next = NULL;
head = pre;
还有一种利用递归的方法。这种方法的基本思想是在反转当前节点之前先调用递归函数反转后续节点。源代码如下。不过这个方法有一个缺点,就是在反转后的最后一个结点会形成一个环,所以必须将函数的返回的节点的next域置为NULL。因为要改变head指针,所以我用了引用。算法的源代码如下:
linka* reverse(linka* p,linka*& head)
if(p == NULL || p->next == NULL)
head=p;
return p;
else
linka* tmp = reverse(p->next,head);
tmp->next = p;
return p;
参考技术A
扣着的是头节点(头子)
车是首节点(首子)
马是次节点(次子)
牙签细的是指针指向,香头发黑的是指向,铁头细的是指向。
根据步骤写程序的伪算法(3步4循环,7张图片搞定),如下:
以下是while循环(条件:香头指向不为空)
第一个循环把马弄到车前面,
第二个循环把相弄到马前面
第三个循环把士弄到相前面
........
直到香指向为空后停止循环。
代码如下:只需要一个首结点pHead,就能把链表找到,并倒置。具体代码如下
p香=pHead->pNext;
p铁=p香->pNext;
p香->pNext=NULL;
P香=p铁
while(p香 !=NULL)
p铁=p香->pNext;
p香->pNext=pHead->pNext;
pHead->pNext=p香;
p香=p铁;
对照伪算法(三步四循环),和上面的代码是一一对应的:
第一步:香头指向首子,铁头指向次子
第二步:删掉首子指向次子(铁头所指向的那个子)的牙签
第三步:香头跟着铁头
以下循环条件:(条件:香头指向不为空)
循环1:铁头移动到香头的下一个指向
循环2:香头的下一个指向首子
循环3:头子的下一个跟着香头
循环4:香头跟着铁头
自己用道具操作几遍,然后把流程背会,以后自己根据流程写代码即可。
java算法leetcode_对话之反转链表
人物:
两个人,我,小铮.
我 : 今天,我来讲解如何反转链表.
> 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;
按理说只要两个就可以了呀,当前下一个(地址).不需要知道上一个的地址.知道上一个是不是就是双向链表? 对的.
小铮 : 小哥哥真厉害.
以上是关于如何链表反转的主要内容,如果未能解决你的问题,请参考以下文章