参考代码随想录的视频:
帮你拿下反转链表 | LeetCode:206.反转链表 | 双指针法 | 递归法_哔哩哔哩_bilibili
题目:
也可参考力扣的这道题目

cpp
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
ElementType Data;
PtrToNode Next;
};
typedef PtrToNode List;
List Read(); /* 细节在此不表 */
void Print( List L ); /* 细节在此不表 */
List Reverse( List L );
int main()
{
List L1, L2;
L1 = Read();
L2 = Reverse(L1);
Print(L1);
Print(L2);
return 0;
}
/* 你的代码将被嵌在这里 */

解析一下题目
这里只需要写一下单链表的逆转函数,不需要其他的输入输出函数。
思路:
双指针:
初始化:
给核心指针赋初始值
实现单链表反转的第一步,是定义并初始化三个核心指针,这是整个反转逻辑的起点:
struct Node *prev = NULL; // 前驱指针,初始指向空(反转后链表的尾端默认是空)
struct Node *curr = L; // 当前遍历指针,初始指向原链表的头指针L(从第一个节点开始遍历)
struct Node *temp = NULL; // 临时后继指针,初始为空(用来暂存当前节点的下一个节点,避免链表断裂)
这里要先明确,struct Node是链表节点的核心结构体,包含数据域Data和指针域Next,也是我们定义所有链表指针的基础;而L是传入反转函数的原链表头指针,指向原链表第一个有效节点。这三个指针的初始值设定,是为了后续遍历和反转做足准备 ------ 前驱指针指向空,保证反转后的链表尾端正确;当前指针从表头开始,确保不遗漏任何节点;临时指针先置空,后续用来保护链表不 "断裂"。
核心:
循环执行中:每一轮的指针调整
初始化完成后,就进入while循环逐节点反转指针,每一轮循环里都会按固定顺序执行 4 步操作,这也是反转的核心环节:
1. 先暂存后继节点: temp**= curr->Next;**
这一步是为了保护链表不丢失后续节点 ------ 如果不把当前节点curr的下一个节点地址存到next里,后续修改curr->Next的指向后,原链表的后续节点就会彻底找不到,链表直接 "断链"。
2. 反转当前节点指针:curr->Next = prev;
这是真正完成 "反转" 的关键一步:把当前节点原本指向 "后一个节点" 的指针,改成指向 "前一个节点"(也就是prev),节点的指向方向从 "正向" 变成 "反向"。
3. 前驱指针后移:prev = curr;
prev需要跟在curr后面移动,接手当前节点的地址,为下一个节点的反转做好准备 ------ 毕竟下一轮循环,当前节点就会变成 "前驱节点"。
4. 当前指针后移:curr = next;
curr跳到之前暂存的next节点,继续遍历原链表的下一个节点,确保所有节点都能被反转。
举个例子,假如原链表是1→3→4→5→2→NULL,第一轮循环会把1的Next指向NULL,第二轮把3的Next指向1,第三轮把4的Next指向3...... 每一轮循环都在调整一个节点的指向,链表的反转就是这样一步步完成的。
结束循环的条件:curr == NULL
整个循环的执行条件是while (curr != NULL),简单说就是:只要curr指向有效节点(不是空),就会继续反转;当curr变成NULL时,循环就会终止。
循环终止时的指针状态很关键:此时curr已经走到原链表最后一个节点的 "下一个位置"(也就是空指针的位置),不再指向任何有效节点;而prev会停在原链表的最后一个有效节点上(比如上面例子里的2),这个节点正好是反转后链表的第一个节点。
返回值:返回 prev 指针
循环结束后,反转函数最终要返回prev指针 ------ 因为此时prev指向的是反转后链表的头节点,而curr和next都是 NULL,只有prev能代表反转后的完整链表。
还是拿刚才的例子来说,循环结束后prev指向节点2,返回这个指针后,我们就能得到2→5→4→3→1→NULL的反转链表,完全符合单链表反转的需求。
最后总结一下整个逻辑:从原链表头开始,用临时指针保护后续节点不丢失,逐个反转当前节点的指向,直到遍历完所有节点(curr 变为 NULL),最后返回此时的 prev 指针,就是反转后链表的头节点。整个过程的核心是指针的有序调整,只要理清每一步指针的指向变化,单链表反转就很好理解了。
手写笔记


手写笔记
递归:
待拓展,敬请期待
答案:
注意:NULL大写,Next大写,以及中英文的指针,PtrToNode ≡ struct Node *
这里是pta的答案
cpp
List Reverse( List L ){
// PtrToNode 这个就是 struct Node;
// 初始化,注意大小写
PtrToNode pre=NULL;
PtrToNode cur=L;//L是头指针
PtrToNode temp=NULL;
// while括号中是循环能够进行的条件
while(cur){
temp=cur->Next;
cur->Next=pre;
pre=cur;
cur=temp;
}
return pre;
}
这里是力扣,c语言版的答案
cpp
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* cur=head;
struct ListNode* pre=NULL;
struct ListNode* temp=NULL;
while(cur){
temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
return pre;
}
初始化pre不同写法的原因:
不同写法
struct Node *pre=NULL;
// PtrToNode pre=NULL;
// List pre=NULL
原因
typedef struct Node *PtrToNode;
struct Node {
ElementType Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
1.结构体名字Node,Node类型的指针
2.typedef struct Node *PtrToNode;提前声明Node的指针叫做PtrToNode,可以直接写
PtrToNode pre =NULL;一级指针
3.PtrToNode别名是List,typedef PtrToNode List;
可以直接写
List pre =NULL;一级指针