单链表的逆置

单链表的逆置,心中永远的记忆。

单链表的逆置可以有多种实现方法,本文算是对逆置问题的一个总结:

首先是使用三指针方法实现。三指针就是使用三个指针分别记录操作每个结点的前驱结点,本身结点,后驱结点。通过while循环不断的调整顺序,然后逐点后移进行操作。这中国三指针的方式应该是最简单的方式,也应该优先考虑的。

LNode*  ReverseList(LNode* head)
{
	if (head == NULL)
		return NULL;
	if (head->next == NULL)
		return head;
	LNode* pre = NULL;
	LNode* Cur = head;
	LNode* Nex = NULL;
	while (Cur!=NULL)
	{
		Nex = Cur->next;
		Cur->next = pre;
		pre = Cur;
		Cur = Nex;
	}
	return pre;
}
因为当年对于单链表的逆置操作,大牛提示我可以考虑递归解决,但是对于递归的方法,自己也是迷糊,要说不明白吧还略懂一二,要说明白吧自己搞还整不动。今天费劲九牛二虎之力总算写了一个解法。
LNode* ReverList(LNode* head,LNode*& headl)
{
	if (head == NULL)
		return NULL;
	if (head->next == NULL)
	{
		headl = head;//返回结点头
		return head;
	}
	if (head->next != NULL)
	{
		LNode* Node = head; //保留上一个结点
		LNode* TempNode = ReverList(head->next,headl);
		TempNode->next = Node; //逆置
		Node->next = NULL; //这句必须有,否则会产生循环链表
		return Node;//返回逆置链表的尾结点
	}
}
上面的实现根据以下几点:

1. 对于链表操作要有安全检查,判断头结点是否为空。

2. 递归实现就要有结束点,对于本文的结束点就是寻找到最后一个结点,同时也可理解为链表只有一个结点时直接返回即可。

3.关于递归,返回了最后的结点,必须实现逆置,逆置即改变结点指针的指向,因此还必须保存前一个结点(LNode* Node = head),使用当前结点指向前一个结点。

4.前一个结点的next必须为NULL,否则最后退出时,会产生循环链表。如果输出的时候会输出3->2->1->2->.......->1->........的死循环(对于此问题的解决,可以递归设置两个参数(pre,cur),调用的时候pre=NULL)


5. 在每层递归结束是都要返回逆链表的尾节点,为上一层递归的逆置做准备。

6. 逆链表的第一个结点就是原链表的尾节点,但是对于递归的退出自己仍旧很迷惑,因此添加了head1用来存储逆链表的头结点,使用的引用类型。

总结:很不理想。

收获:递归其实就是一个进栈出栈的过程,进入递归下一层就是新的入栈过程,在新的栈里面可以保存已知的各种信息,就像此题目,不仅可以保存head,还可以保存head->next.当底层函数出栈返回到此栈后,这些保存的信息仍然是可以使用的,而自己最开始只是想到保存一个结点head,head->next需要通过返回值指定,明显多此一举,同时也是对递归的理解不够深刻造成的。
       对于链表的每个结点都要明确的它的next,防止出现断链或者循环。对于测试用例可以包括NULL,只有一个结点等特殊情形。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

由于使用引用的方式很不好,也没见递归会使用引用的方式返回,因此参考了踏雪无痕的博客,对自己的程序进行了反思,发现可以在进入递归前就存储好当前结点与下一结点。让递归的返回值始终都是逆链表的首结点。

LNode* ReverList1(LNode* head)
{
	if (head == NULL)
		return NULL;
	if (head->next == NULL)
	{
		return head;
	}
	LNode* Node = head; //保留上一个结点
	LNode* Nex = head->next;
	LNode* HeadNode = ReverList1(Nex);
	Nex->next = Node; //逆置
	Node->next = NULL; //这句必须有,否则会产生循环链表
	return HeadNode;//返回逆置链表的尾结点
	
}

本递归的特点:

1.在进入递归时就保存当前结点与下一结点。使用下一结点进行递归结束判断。

2.递归返回值始终携带的是原链表的尾结点,逆链表的首结点。递归的返回过程都没有影响。

3.逆置操作时使用的是在进入递归前就存储好的相邻结点。对返回的首结点没影响。可以考虑为入栈的过程:在每次进栈的时候就存储好当前结点与下一结点,递归就是不断的入栈,递归的返回就是不断的出栈。逆置就是使用存储好的相邻结点来完成逆置操作。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

进栈的时候直接不保存,直接使用

LNode* Re(LNode* head)
{
	if (head ==NULL)
		return NULL;
	if (head->next == NULL)
		return head;
	LNode* Node = Re(head->next);
	head->next->next = head;
	head->next = NULL;
	return Node;
}



你可能感兴趣的:(单链表的逆置)