如何将单链表逆转(超详细)

单链表逆转的方法有很多,我也从很多博主那学习看到了各种各样的方法。今天就给大家总结一下个人认为较简便的四种方法。这四种方法不用开辟新的空间,所以不会造成空间浪费。

方法一:迭代

 采用迭代的基本思路如下:我假设链表为1->2->3->4,那么但我完成链表的逆转后就应该是4->3->2->1。我将链表的头结点设为L,同时开辟两个新的节点q和p,我将利用L,q,p三个节点来进行迭代。

List Reverse(List L) {
		List p, q;
		p = L;
		L = NULL;
		while (p)
		{
			q = p;
			p = p->Next;
			q->Next = L;
			L = q;


		}
		return L;

	}

 代码在上面,具体的思路讲解如下:

L为头节点,把L赋值给p,而后让L为null。如下

如何将单链表逆转(超详细)_第1张图片

进入while循环体进行第一次的循环,如下

如何将单链表逆转(超详细)_第2张图片

当p不为空,进行第二次循环。如下

如何将单链表逆转(超详细)_第3张图片 

当p不为空,进行第三次循环,第四次.........到p为空为止。当while循环体执行到p为空的时候,这时最后一个节点为L,返回L,逆转结束。

(本质是有三个节点分别为L,q,p。进行while循环后,每次改变一个节点的方向,让原来为L->q的方向,变成q->L。然后通过迭代让q变成新的L,p变成新的q,p=p->next变成新的p,在下一个循环继续改变方向。)

 

 方法二:不同风格的迭代

第二种方法也是迭代,但和第一种方法相比会有所不同。核心思想一样,通过不断移动三个点来实现方向的转变。

头节点为L,新开辟三个新的节点空间为p,q,r。

List Reverse(List L) {
		List p, q, r;
		if (L == NULL || L->Next == NULL) //当头节点为空或者只有一个节点时直接返回头节点。
			return L;
		p = L;
		q = L->Next;
		L->Next = NULL;
		while (q) {
			r = q->Next;
			q->Next = p;
			p = q;
			q = r;
		}
		L = p;
		return L;

	
	}

 代码在上面,具体的思路讲解如下:

头节点赋给p,头节点下一个为q,然后让头节点指向null。如下

如何将单链表逆转(超详细)_第4张图片

 进行第一次的循环 ,如下如何将单链表逆转(超详细)_第5张图片

当q节点不为空,进行第二次循环,如下

如何将单链表逆转(超详细)_第6张图片

  继续进行循环,直到当q节点为空时,这最后一个节点为p,退出循环。将p设为新的头节点L,返回L。

 方法三:

从第2个节点到第N个节点,依次逐节点插入到第1个节点(L节点)之后,最后将第一个节点挪到新表的表尾。  

List Reverse(List L) {
		if (L == NULL || L->Next == NULL)return L;//当为空链表或者只有一个节点时返回L
		List p, q;
		p = L->Next;
		while (p->Next) {
			q = p->Next;
			p->Next = q->Next;
			q->Next = L->Next;
			L->Next = q;
		}
		p->Next = L;
		L = p->Next->Next;
		p->Next->Next = NULL;
		return L;
		
	}

代码在上面,具体的思路讲解如下:

假设链表为1->2->3->4->5->6,我们的步骤如下:

如何将单链表逆转(超详细)_第7张图片

 具体的步骤如下:

当开始执行时(写得有些潦草,诸位多多包涵,耐心看一定有所收获)

如何将单链表逆转(超详细)_第8张图片

 当继续循环时

如何将单链表逆转(超详细)_第9张图片

当循环结束时,我们会得到1->6->5->4->3->2。这明显不是我们想要的结果,但离最终结果已经很近了,我们如何将原始的头节点移到最后呢?

因为循环条件是p->next不为空,那么我们已经知道了当循环退出时最后一个节点为p。于是我们可以(1)让p->Next = L,形成一个闭环。(2) L = p->Next->Next形成新的头节点。(3)最后用p->Next->Next = NULL来切断闭环,形成一个链表。还是有点懵?不要紧,我把图画好了!诸君请细看。

(1)让p->Next = L,形成一个闭环

如何将单链表逆转(超详细)_第10张图片

 (2) L = p->Next->Next形成新的头节点

如何将单链表逆转(超详细)_第11张图片

 最后用p->Next->Next = NULL来切断闭环,形成一个链表如何将单链表逆转(超详细)_第12张图片

 最后三步的总图在这

如何将单链表逆转(超详细)_第13张图片

 方法四:递归

用递归来实现代码上会相对的简单。关于递归这,我看了几篇博主的文章,有几个版本,大家看看哪个才是对的。

(1)版本一:有的博主是这样认为的,比如链表是1->2->3->4->5->6,他认为递归函数Reverse()执行完后,链表就变成了6->5->4->3->2 <-1,然后只需要改动原来的头节点就可以完成逆转。通俗的说就是不断继续递归找到新节点,然后执行递归后面的语句只执行一次改变头节点就完成了。

(2)版本二:通过不断的递归,每次递归都会执行递归后面的语句,每次改变两个节点之间的方向,从前往后改,基本是这样的1<-2->3->4->5->6,然后1<-2-<3->4->5->6,然后1<-2<-3<-4->5->6以此类推。

(3)这既然是一个有争议的地方,我个人是这样认为的,递归后的语句应该是在完成递归后再不断执行,递归多少次就执行多少次,和版本二一样,但执行的顺序我认为应该是从后往前,因为它是堆栈存储,应该遵循后进先出,所以我认为应该是1->2->3->4->5<-6,然后1->2->3->4<-5<-6,然后1->2<-3<-4<-5<-6,以此类推。

但无论是哪个版本,下面这些递归代码答案都是正确的,而且极其简短。

List Reverse(List L) {
		if (L == NULL || L->Next == NULL)return L;//当L为空或者只有L一个节点时
		List newL, q;
		newL = Reverse(L->Next);
		q = L->Next;
		q->Next = L;
		L->Next = NULL;
		return newL;

头节点为L,当逆转链表后,新的头节点为newL;

总结:上面这四种方法不用另外开辟空间,不会造成空间浪费。也是我认为较好的方法。虽然有些地方可能写的可能比较潦草,但我也是收集了几天资料,看了许多博主后个人总结写的,上面内容均为原创,个人认为也算是心血之作了,不知不觉已经2000多字了,希望能帮助到大家,大家也不要吝啬手中的赞哦,喜欢的朋友赞一个。

你可能感兴趣的:(数据结构与算法,链表)