题目来源
题目描述
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
class Solution {
public:
ListNode* reverseList(ListNode* head) {
}
};
题目解析
链表逆序的本质,就是把每一个节点原本指向下一个节点的next指针倒转过来,指向它的前置节点
递归
- 使用递归函数,一直递归到链表的最后一个结点,该结点就是反转后的头结点,记作 ret .
- 此后,每次函数在返回的过程中,让当前结点的下一个结点的 next 指针指向当前节点。
- 同时让当前结点的 next指针指向 NULL ,从而实现从链表尾部开始的局部反转
- 当递归函数全部出栈后,链表反转完成。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == nullptr || head->next == nullptr){
return head;
}
ListNode *ret = reverseList(head->next);
head->next->next = head; // 我【head】的下一个节点【next】指向【next】指向我自己【head】
head->next = nullptr; // 我自己【head】指向【next】空【null】
return ret;
}
};
双指针(原地反转⭐)
- 定义两个指针: front 和 rhead ;front 在前 rhead 在后。
- 每次让 front 的 next指向 rhead ,实现一次局部反转
- 局部反转完成之后, front 和 rhead 同时往前移动一个位置
- 循环上述过程,直至 rhead 到达链表尾部
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == nullptr){
return nullptr;
}
ListNode *rHead = nullptr, *front = head;
while (front != nullptr){
ListNode *t = front->next;
front->next = rHead;
rHead = front;
front = t;
}
return rHead;
}
};
针对链表的某个节点,如果要把它的next指针倒转,至少需要三个节点。
让我们从链表头部开始,建立三个临时节点的引用,分别为p1,p2,p3。它们分别指向头节点、第二个节点、第三个节点。
实现链表逆序的完整步骤如下:
1.以p2节点为视角,把p2节点原本指向p3的next指针倒转,指向p1。
2.三个临时节点引用p1,p2,p3分别向后移动一格位置。
3.重复第1步的工作,以p2节点为视角,把p2节点原本指向p3的next指针倒转,指向p1。
4.重复第2步的工作,三个临时节点引用p1,p2,p3分别向后移动一格位置。
5.继续像这样子迭代下去,一直到p2是空为止。
6.最后,把head节点的next指向空,成为逆序链表的尾节点。并且把p1赋值给head,让p1所在的节点成为逆序链表的头节点。
头插法(不推荐,面试写这个没分,笔试的时候用)
遍历已有链表,对每个元素实行头插法插入到一个新的链表当中从而完成逆序。
ListNode* reverseList(ListNode* head) {
if(head == NULL){
return NULL;
}
ListNode *dummy = new ListNode(head->val), *newNode;
ListNode *iter = head;
while (iter){
newNode = new ListNode(iter->val);
newNode->next = dummy->next;
dummy->next = newNode;
iter = iter->next;
}
return dummy->next;
};
扩展:双链表反转
class Code01_ReverseList{
struct Node{
int value;
Node * next;
Node(int data) : value(data){
}
};
struct DoubleNode{
int value;
DoubleNode *prev;
DoubleNode *next;
DoubleNode(int data) : value(data){
}
};
public:
// head
// a -> b -> c -> null
// c -> b -> a -> null
static Node* reverseLinkedList(Node* head){
if(head == nullptr || head->next == nullptr){
return head;
}
Node *pre = nullptr, *curr = head, *next = nullptr;
while (curr != nullptr){
next = curr->next;
curr->next = pre;
pre = curr;
curr = next;
}
return pre;
}
static DoubleNode *reverseDoubleList(DoubleNode *head){
if(head == nullptr || head->next == nullptr){
return head;
}
DoubleNode *prev = nullptr, *curr = head, *next = nullptr;
while (curr != nullptr){
next = curr->next;
curr->next = prev;
curr->prev = next;
prev = curr;
curr = next;
}
return prev;
}