链表(两两交换链表中的节点)(2)

https://blog.csdn.net/2601_95366422/article/details/159051445

上节课连接

一.题目

24. 两两交换链表中的节点 - 力扣(LeetCode)

二.思路讲解

2.1 思路讲解

首先,题目要求我们交换链表中的相邻节点 ,比如将第1个和第2个节点交换,第3个和第4个节点交换,以此类推。这里有一个关键点:我们不能只交换节点的值 ,而必须通过改变节点的指针指向来实现真正的节点交换,因为链表的结构决定了节点本身的位置关系。

在操作链表时,为了避免处理头节点时的边界问题,我们通常需要引入一个虚拟头节点(也叫哨兵位)。这个虚拟头节点指向原链表的第一个节点,这样在交换前两个节点时,我们可以统一地使用一套逻辑,而不需要单独判断头节点的情况。

接下来,我们分析如何交换两个相邻节点。假设我们要交换节点 AB ,其中 AB 的前驱。那么我们需要关注四个关键节点:

  • prev :指向 A 的前一个节点(对于头节点,prev 就是虚拟头节点)。

  • cur :指向要交换的左节点 A

  • next1 :指向要交换的右节点 B

  • next2 :指向 B 的下一个节点,即交换后需要接上的后续部分。

有了这四个节点,我们就可以进行指针的重新连接。具体步骤是:

  1. prevnext 指向 B ,这样 B 成为新的左节点。

  2. curnext 指向 next2 ,因为 A 要换到后面,它应该指向原来的后续部分。

  3. Bnext 指向 cur ,这样 B 后面就接上了 A

完成这两个节点的交换后,我们需要继续处理下一对相邻节点。此时,原来的 cur (即现在的 A )已经成为了这一对的后一个节点,而下一对要交换的是 A 后面的两个节点。因此,我们需要更新四个指针的位置:

  • 新的 prev 应该指向当前这一对的后一个节点,即 cur

  • 新的 cur 应该指向 next2(即下一对的第一个节点)。

  • 新的next1 应该指向cur->next

  • 新的next2 应该指向next1->next

三.代码演示

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head)
    {
        //如果没有两个节点那么无法交换
        if(head == nullptr || head->next == nullptr)
            return head;

        ListNode* new_head = new ListNode;
        new_head->next = head;//让虚拟头节点和头节点连接
        ListNode* prev = new_head;//父节点
        ListNode* cur = head;//要交换的左边节点
        ListNode* next1 = head->next;//要交换的右边节点
        ListNode* next2 = next1->next;//右边节点的下一个节点

        while (cur != nullptr && next1 != nullptr)
        {
            //交换左右节点
            prev->next = next1;//父和右连接
            next1->next = cur;//右和左连接
            cur->next = next2;//左和右边界的下一个节点连接

            prev = cur;
            cur = next2;
            if(cur != nullptr)
                next1 = next2->next;
            if (next1 != nullptr)
                next2 = next1->next;
        }
        return new_head->next;
    }

};

四.代码讲解

一、虚拟头节点与边界判断

在链表操作中,为了统一处理头节点的特殊情况,我们首先创建一个虚拟头节点 new_head,并将其 next 指向原链表的头节点 head。这样,无论头节点是否参与交换,我们都可以用一套逻辑操作。同时,我们检查链表是否至少有两个节点:如果 head == nullptrhead->next == nullptr,则无法交换,直接返回原链表。

二、初始化四个关键指针

我们需要记录交换过程中涉及的四个关键节点:

  • prev :指向当前要交换的两个节点的前一个节点,初始化为虚拟头节点 new_head

  • cur :指向要交换的左节点,初始化为 head(即第一个节点)。

  • next1 :指向要交换的右节点,初始化为 head->next(即第二个节点)。

  • next2 :指向右节点的下一个节点,即交换后需要接上的后续链表,初始化为 next1->next

这四个指针的初始状态正好对应第一对节点(节点1和节点2)及其前后关系。

三、循环交换每一对节点

进入 while 循环,条件为 cur != nullptr && next1 != nullptr ,即当前还有一对节点可以交换(左节点和右节点都存在)。在循环体内,执行以下三步完成交换:

  1. prevnext 指向 next1 这一步让前一节点直接指向右节点,使得右节点成为新的左端。

  2. next1->next 指向 cur 这一步让右节点指向左节点,完成两个节点的反转。

  3. cur->next 指向 next2 这一步让左节点指向原来的后续链表,保证链表不断开。

经过这三步,原来的 cur(左节点)和 next1(右节点)位置互换,且链表连接正确。

四、更新指针准备下一轮交换

交换完成后,我们需要将四个指针移动到下一对节点的位置,以便继续处理。更新顺序如下:

  • prev = cur :因为 cur 现在已经是这一对中靠后的节点,下一对的前一个节点就是它。

  • cur = next2next2 原本是下一段的开头,现在作为下一对的左节点。

  • 接着,需要重新确定 next1next2

    • 如果 cur 不为空,则 next1 = cur->next(即下一对的右节点)。

    • 如果 next1 不为空,则 next2 = next1->next(即再下一个节点)。

注意,这里需要先判断 cur 是否为空,再取 cur->next,防止空指针访问。同样,next1 可能为空,也需要判断后赋值 next2。这种逐步更新的方式保证了指针始终有效。

五、循环结束与返回

curnext1nullptr 时,说明没有更多可交换的节点(可能是只剩一个节点或已到末尾),循环结束。最后,返回 new_head->next,即虚拟头节点的下一个节点,也就是交换后链表的新头节点。

六、关键细节
  • 虚拟头节点的必要性:避免了在交换头两个节点时需要单独处理前驱为空的边界,使代码统一简洁。

  • 四个指针的精确维护 :交换过程中,必须确保每一步指针的修改不会丢失后续链表的引用,特别是 next2 的提前保存至关重要。

  • 循环条件的动态性 :每次交换后,curnext1 都可能变为空,因此循环条件在每次迭代前判断,确保安全。

  • 指针更新的顺序 :先移动 prevcur,再根据新的 cur 重新获取 next1next2,这种顺序保证了指针的连续性。

相关推荐
程序猿乐锅15 分钟前
【Tilas|第三篇】多表SQL语句
数据库·经验分享·笔记·学习·mysql
徐某人..21 分钟前
基于i.MX6ULL平台的智能网关系统开发
arm开发·c++·单片机·qt·物联网·学习·arm
AOwhisky42 分钟前
Kubernetes 学习笔记:集群管理、命名空间与 Pod 基础
linux·运维·笔记·学习·云原生·kubernetes
无敌秋1 小时前
# C++ 简单工厂模式实战指南
c++·简单工厂模式
code_pgf1 小时前
Octo 算法详解-开源通用机器人策略模型技术报告
算法·机器人·开源
cany10001 小时前
C++ -- 模板的声明和定义
开发语言·c++
澈2071 小时前
深耕进阶 Day1:C 与 C++ 核心差异 + C++ 入门基石
c语言·开发语言·c++
嘻嘻哈哈樱桃1 小时前
牛客经典101题题解集--动态规划
java·数据结构·python·算法·职场和发展·动态规划
光影少年1 小时前
大屏页面,一次多个请求,请求加密导致 点击 全局时间选择器 时出现卡顿咋解决(面板收起会延迟1~2秒)
前端·javascript·vue.js·学习·前端框架·echarts·reactjs