关于链表(单向)的反转,常用的就是迭代方式和递归方式,网上有很多相关的讲解,花了些时间才弄懂,为了加深理解记忆,特意写了篇博客。
这是第一次写博客,纯属个人见解,有任何不妥地方,请各位多多包涵、指正。
一、迭代方式
这是个人认为比较容易理解的,迭代是从表头开始处理,依次将每个节点变成新的表头,并将其地址域指向上一个节点(即旧的表头,若为第一个节点,则地址域指向NULL),以下面链表作为例子:
(1)指针P指向表头,开始处理
(2)节点1作为新表头,其地址域指向NULL,实际上就是新表尾,指向P移动至2
(3)节点2地址域指向上一步的新表头(即节点1),节点2作为新表头,指向P移动至3
(4)类似的,节点3地址域指向上一步的新表头(即节点2),节点3作为新表头
(5)至此,完成链表反转
(4)代码
struct ListNode* reverseList(struct ListNode* head)
{
if((head == NULL)||(head->next == NULL))
{
return head;
}
struct ListNode *p,*p_tmp,*new_head;
p = head;
new_head = NULL;
while(p)
{
p_tmp = p->next;
p->next = new_head;
new_head = p;
p = p_tmp;
}
return new_head;
}
二、递归方式
递归方式则需要用到递归函数,递归函数平时用的不多,而且若是脑回路不够,就容易出问题,所以比较难理解。我发现造成难理解的一个小原因是很多讲解说明给出的示例链表节点太多,加上递归的原因,就比较难理解了。
代码就是以下几行,有时绞尽脑汁也想不懂这几行代码竟然能实现反转,这就是这个算法的魅力。(与迭代方式不同,递归方式是从表尾开始处理的,由于表尾就是真正的新表头,所以从始至终都不变)
struct ListNode* reverseList(struct ListNode* head)
{
if((head == NULL )||(head->next==NULL))
return head;
struct ListNode *new_Head = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return new_Head;
}
1、首先以最简单的两个节点链表为例
(1)以节点1为表头传入,在reverseList(head->next)处递归一次(代码块2),传入的是节点2,由于节点2为表尾,不再递归,返回节点2地址,用新表头new_Head接收,于是节点2成为新表头
(2)再注意下面两行代码,head->next就是节点2,所以head->next->next = head;就是将节点2地址域指向节点1
(3)接着 head->next = NULL;就是将节点1地址域指向NULL,作为新表尾
(3)返回新表头new_Head(即节点2),至此反转完成
2、以上就是最简单链表递归反转,再长一点的链表就是以上面为基础进行拓展,如以三个节点链表为例,仅仅增加一个节点0
(1)同理,reverseList()会递归两次(代码块2、3),递归两次返回其实就是上面例子的结果
(2)同理,接下来两行代码,将节点1地址域指向节点0,节点0地址域指向NULL,即新表尾
(3)至此,三个节点的链表反转完成