题目描述(来源)
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
如下为图解
思路
思路一(双指针)
从前向后遍历链表,然后把每个结点的 next 指向前一个结点就好。
具体实现中,首先需要两个指针,一个 cur 指针在遍历到每个结点进行操作,一个 prev 指针指向 cur 的前一个结点。其次,由于 cur->next 指向 prev,导致原来的 cur 的下一个结点失去引用,所以还需要一个指针 temp 用来保存后一个结点。
struct ListNode* reverseList(struct ListNode* head)
{
// 初始化两个指针,cur 用于遍历链表,初始时指向头节点
struct ListNode* cur = head;
// 初始化一个指针 prev 用于暂存每个节点的前一个节点,初始时 prev 为 NULL
struct ListNode* prev = NULL;
// 当 cur 不为空时,执行循环
while (cur)
{
// 临时存储 cur 节点的下一个节点(即将被 cur 节点覆盖的下一个节点的地址)
struct ListNode* temp = cur->next;
// 修改 cur 节点的 next 指针,使其指向 prev 节点,即完成了一次节点间的翻转连接
cur->next = prev;
// prev 和 cur 同时向前移动一步,prev 移动到 cur 的位置,cur 移动到下一个节点的位置
prev = cur;
cur = temp;
}
// 当循环结束时,prev 指针指向了原链表的新头部,因此返回 prev 作为翻转后链表的新头节点
return prev;
}
思路二(递归法)
递归法和双指针法是一样的逻辑,同样是当 curr 为空的时候循环结束,不断将 curr 指向 pre 的过程。
struct ListNode* reverseList(struct ListNode* head)
{
// 基线条件:如果头结点为空或者只有一个结点,无需反转,直接返回头结点
if (head == NULL || head->next == NULL)
{
return head;
}
// 递归调用,将后续部分链表反转,并获取反转后的尾结点
struct ListNode* newTail = reverseList(head->next);
// 将尾结点的next指针指向当前头结点,完成局部反转
head->next->next = head;
// 更新当前头结点的next指针,使其指向NULL,成为新的尾结点
head->next = NULL;
// 返回新的头结点,即原链表的尾结点
return newTail;
}