图解反转链表的4种方法


声明:本文为博主原创文章,未经允许不得转载。如有问题,欢迎指正!

206. 反转链表 (简单)
题目描述:

反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
链接:https://leetcode-cn.com/problems/reverse-linked-list/

方法一:

遍历原链表,把“当前结点”按照头插法添加到新链表中。思路简单,图解略去。

 / /java代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
    ListNode Reverse=null;    / /定义新链表
    ListNode temp=head;       / /temp用于遍历
    while(temp!=null){        
    ListNode cur=new ListNode(temp.val);  / /生成新结点
    if(Reverse==null) Reverse=cur;    / /Reverse为空时直接指向新结点   
    else{             / /Reverse非空时执行头插:   
    ListNode p=Reverse;    / /1.用p标记Reverse(记录头结点)
    Reverse=cur;           / /2.Reverse指向新结点cur (更改头结点) 
    Reverse.next=p;        / /3.新的头结点与之前链表连接
    }
    temp=temp.next;    
    }
    return Reverse;
    }
}
方法二:

== 双指针解法== 既然是反转,就把原来的“指向”反过来。遍历链表,把当前结点cur指向cur的上一个结点,因为单向链表不能“由当前结点知道上一个结点”,故用pre记录前一个结点。如果只有前面的操作,那cur原本的后继结点就找不到了,故应该先用record将其保存。

/ /java代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur=head;   / /cur用于遍历链表
ListNode pre=null;/ /pre为当前结点cur的上一个结点。初始化为null,因为最开始的pre最终变为尾
while(cur!=null){
ListNode record=cur.next; / /1.记录cur的下一个结点,以防在 cur.next=pre 后找不到“原来的下一个”
    cur.next=pre;         / /2.当前的“指针”指向上一个
    pre=cur;              / /3.pre后移
    cur=record;           / /4.cur指向下一个结点
    } 
    return pre;
    }
}
方法二图解

以下是链表为1->2->3->4->null 时具体的双指针操作过程示例:
在这里插入图片描述

方法三:

迭代法

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
    ListNode cur=head;
    if(head==null) return null;
    while(head.next!=null){
    ListNode record=head.next.next;
    head.next.next=cur;
    cur=head.next;
    head.next=record;

    }
    return cur;

    }
}
方法三图解

以下是链表为1->2->3->4->null 时具体的迭代过程示例:
在这里插入图片描述

方法四:

递归解法:递归解法可由迭代演化过来。(大部分迭代和递归都可以相互转化)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
    if(head==null||head.next==null)  return  head;
    ListNode newHead=reverseList(head.next);
    head.next.next=head;      
    head.next=null;
    return newHead;
    }
}
方法四图解

以下是链表为1->2->3->4->null 时主要的调用和回退过程(橙色结点为递归或回退到的“当前结点”):
在这里插入图片描述

上一篇博客:leetcode 78 子集 (位运算)

<think> 首先,用户查询是:“我想查找关于链表图解资料 请问链表图解资料”。这似乎是关于链表图解的请求。用户提到“链表图解资料”,意思是链表图解资料。 在系统级指令中,我有引用[1]、[2]、[3]和[4]: - 引用[1]: 关于双向链表、循环链表的创建图解。 - 引用[2]: 图解链表反转系列。 - 引用[3]: FreeRTOS源码解读中的链表图解。 - 引用[4]: 合并两个有序链表图解。 这些引用提供了关于链表的各种图解资料。用户说“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答”。但在对话历史中,用户上一次问题是:“我想查找关于链表图解资料 请问链表图解资料”,这是第一次查询。 在之前的对话中,有一个示例关于快速排序,但那不是用户查询;那是系统指令的一部分。用户的实际查询是当前的这条。 用户说:“参考站内引用:引用[1]...引用[4]”,所以我应该基于这些引用来回答,但记住它们是参考,并不是用户真正需求的完整表达。 用户需求是查找链表图解资料。所以,我需要根据这些引用提供信息。 系统指令要求: - 使用LaTeX格式:行内数学表达式用$...$,独立公式用$$...$$。 - 使用中文回答。 - 生成相关问题。 - 在引用的段落末尾自然地添加引用标识,如[^1]。 回答结构应该清晰,帮助用户逐步解决问题。 结构我的回答: 1. **介绍**:简要解释链表是什么,并提及图解资料的好处。 2. **基于引用提供图解资料**: - 引用[1]:双向链表和循环链表的创建图解。 - 引用[2]:链表反转图解。 - 引用[3]:FreeRTOS中的链表图解。 - 引用[4]:合并两个有序链表图解。 对于每个,简要描述图解内容,并添加引用标识。 3. **总结**:鼓励用户探索这些图解4. **生成相关问题**:最后添加相关问题。 确保语言清晰、结构化。 使用中文。 生成相关问题:基于链表主题,提出相关问题。 例如: - 如何实现链表的插入操作? - 链表反转有哪些常见算法? - 等等。 现在,构建回答。 </think> ### 链表图解资料介绍 链表是一种基础数据结构,由节点组成并通过指针连接,常用于动态内存管理。图解资料能直观展示操作过程(如插入、删除、反转等),帮助理解其逻辑和性能。基于提供的引用,以下是详细的链表图解资料总结(每个部分末尾添加引用标识)。这些资料覆盖了双向链表、循环链表反转操作、操作系统应用和合并算法。 #### 1. **双向链表和循环链表的创建图解** 引用[1]提供了双向链表和循环链表的创建过程图解图解步骤如下: - **双向链表**:每个节点包含数据和指向前后节点的指针(如 `prev` 和 `next`),插入或删除时需更新相邻节点的指针(例如,删除节点需修改前节点的 `next` 和后节点的 `prev`)。 - **循环链表**:尾节点指向头节点,形成一个闭环。图解中展示了创建代码的核心逻辑,如使用 `malloc` 分配内存并设置指针: ```c void creat(LNode*& head) { LNode* p; LNode* temp; head = (LNode*)malloc(sizeof(LNode)); head->next = NULL; p = head; while (true) { temp = (LNode*)malloc(sizeof(LNode)); cin >> temp->data; p->next = temp; p = temp; } p->next = head; // 设置尾节点指向头节点,形成循环 } ``` 图解强调了指针的指向变化(如 `p->next = head`),便于理解如何避免内存泄漏[^1]。 #### 2. **链表反转图解系列** 引用[2]以LeetCode题目为基础,图解链表反转操作: - **LC 206 反转链表**:图解展示了迭代方法,通过三个指针(prev, curr, next)逐步反转节点指向。示例中,初始链表 $1 \to 2 \to 3$ 反转后变为 $3 \to 2 \to 1$。核心在于每次迭代更新指针: ``` 初始:prev = nullptr, curr = head 步骤:while curr: next = curr->next curr->next = prev prev = curr curr = next 结束:head = prev ``` 图解还扩展到更复杂问题,如LC24(两两交换节点)和LC25(K个一组翻转),强调了指针操作的顺序对时间复杂度的影响(平均 $O(n)$)[^2]。 #### 3. **FreeRTOS中的链表图解** 引用[3]解读了FreeRTOS源码中的链表实现,图解了节点移除操作: - FreeRTOS链表基于值排序(Value值),图解展示了如何通过 `uxListRemove` 函数移除节点。代码逻辑包括: - 移除节点时,更新相邻节点的指针(如 `pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious`)。 - 确保索引指针 `pxIndex` 指向有效节点(如果移除节点是索引节点,则回退到前一个节点)。 图解突出链表在实时操作系统中的应用,例如任务调度,并强调了指针操作的原子性以避免竞态条件[^3]。 #### 4. **合并两个有序链表图解** 引用[4]图解了合并两个有序链表(如LeetCode题目): - 图解使用哨兵节点(dummy node)简化过程: - 创建虚拟头节点 `preHead`,通过指针 `prev` 遍历链表。 - 比较链表节点值(例如 $l1.val$ 和 $l2.val$),将较小值追加到新链表。 - 合并剩余部分(如果一个链表已空): ```cpp prev->next = (l1 == nullptr) ? l2 : l1; ``` 图解展示了时间复杂度 $O(n+m)$(n和m分别为链表长度),并强调指针的链接顺序如何避免数据丢失[^4]。 ### 总结与建议 以上图解资料覆盖链表的基本操作到高级应用(如反转、合并和操作系统集成),建议结合代码和图示练习以加深理解。如果您需要具体图解文件或扩展资料,可以提供更多细节。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值