单链表逆转,c语言

参考代码随想录的视频:

帮你拿下反转链表 | LeetCode:206.反转链表 | 双指针法 | 递归法_哔哩哔哩_bilibili

题目:

也可参考力扣的这道题目

LCR 024. 反转链表 - 力扣(LeetCode)

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大写,以及中英文的指针,PtrToNodestruct 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;一级指针

相关推荐
im_AMBER3 小时前
Leetcode 78 识别数组中的最大异常值 | 镜像对之间最小绝对距离
笔记·学习·算法·leetcode
鼾声鼾语4 小时前
matlab的ros2发布的消息,局域网内其他设备收不到情况吗?但是matlab可以订阅其他局域网的ros2发布的消息(问题总结)
开发语言·人工智能·深度学习·算法·matlab·isaaclab
其美杰布-富贵-李4 小时前
HDF5文件学习笔记
数据结构·笔记·学习
LYFlied4 小时前
【每日算法】LeetCode 25. K 个一组翻转链表
算法·leetcode·链表
Swizard4 小时前
别再迷信“准确率”了!一文读懂 AI 图像分割的黄金标尺 —— Dice 系数
python·算法·训练
s09071364 小时前
紧凑型3D成像声纳实现路径
算法·3d·声呐·前视多波束
可爱的小小小狼4 小时前
算法:二叉树遍历
算法
d111111111d5 小时前
在STM32函数指针是什么,怎么使用还有典型应用场景。
笔记·stm32·单片机·嵌入式硬件·学习·算法
明洞日记5 小时前
【数据结构手册008】STL容器完全参考指南
开发语言·数据结构·c++