单链表逆转,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;一级指针

相关推荐
sinat_2869451910 分钟前
opencode
人工智能·算法·chatgpt
HABuo18 分钟前
【Linux进程(四)】进程切换&环境变量深入剖析
linux·运维·服务器·c语言·c++·ubuntu·centos
工口发动机26 分钟前
ABC440DEF简要题解
c++·算法
C++ 老炮儿的技术栈39 分钟前
什么是通信规约
开发语言·数据结构·c++·windows·算法·安全·链表
零小陈上(shouhou6668889)1 小时前
K-近邻算法 - lazy learning的代表
算法·近邻算法
有一个好名字1 小时前
力扣-从字符串中移除星号
java·算法·leetcode
萧瑟其中~1 小时前
二分算法模版——基础二分查找,左边界查找与右边界查找(Leetcode的二分查找、在排序数组中查找元素的第一个位置和最后一个位置)
数据结构·算法·leetcode
码上就好ovo1 小时前
Atcoder Beginnner Contest 440
算法
高洁011 小时前
CLIP 的双编码器架构是如何优化图文关联的?(3)
深度学习·算法·机器学习·transformer·知识图谱