首先,关于递归的知识,可以参考我的这篇 递归:汉诺塔
关于单链表的知识可以参考我的这篇 单链表整表创建的两种方法(头插法和尾插法)
本文中链表的结构定义如下:
typedef struct Node{
int data;
Node *next;
} Node, *List;
想要反转整个链表,可以考虑一个一个的结点从后往前反转,这就考虑到了递归与回溯,所以可以用递归实现:
//递归方式
Node * reverseList(List head)
{
//如果链表为空或者链表中只有一个元素
if(head == NULL || head->next == NULL)
{
return head;
}
else
{
//先反转后面的链表,走到链表的末端结点
Node *newhead = reverseList(head->next); //语句1
//再将当前节点设置为后面节点的后续节点
head->next->next = head; //语句2
head->next = NULL; //语句3
return newhead;
}
}
整个递归算法可以用下面的示意图解释,其实跟汉诺塔是一个道理:
上面代码中的语句1是一个不断向后递归的过程,终止条件是if中的判断部分,实际上就是在偷懒,让“别人”先帮我把除了第一个结点以外的其他结点反转过来,我负责最后一个。
语句2和语句3就是接下来我要做的工作了(我就捡轻松的活干)
语句2
就是下图中我做的第一步,变换一下指针
语句3就是下图中我做的第二步,把最后一个指针指向NULL
最后返回newHead,OK大功告成!
=============================次次用到的华丽分割线===============================
下面讲一下反转链表的迭代版本:
迭代版本需要注意的问题是,当反转一个结点以后的链表断裂问题。
所以这里我们需要设置3个指针,分别指向当前结点、当前结点的前一结点和当前结点的后一结点。
#include <iostream>
using namespace std;
typedef struct Node{
int data;
Node *next;
} Node, *List;
Node * reverseList(List head){
//定义三个指针,保存原来的连接的状态
//当前结点指针
Node *pnow = head;
//当前结点的前驱指针,初始化是 NULL
Node *pre = NULL;
//当前结点的后继指针,初始化也是 null
Node *pnext = NULL;
//定义尾指针
Node *tail = NULL;
//开始遍历链表
while(pnow != NULL){
//如果当前结点不是 null,那么初始化 pnext 指针指向当前结点的下一个结点
pnext = pnow->next;
//如果找到了尾结点,初始化 tail 指针
if(NULL == pnext){
tail = pnow;
}
//进行链表的反转,当前结点的 next 指针指向前一个结点,实现链表方向的反转,此时发生了断链
pnow->next = pre;
//勿忘断链的情形,需要使用 pre 指针保存状态,pre 等价于是后移一个结点
pre = pnow;
//pnow 后移一个结点
pnow = pnext;
}
return tail;
}