C++实现相交链表与反转链表算法详解

月亮慢半拍
月亮慢半拍
发布时间:2026-10-16| 8人浏览过
原创

针对C++开发者在处理链表数据结构时遇到的常见问题,本文深入解析两个经典算法:如何高效定位两条单链表的起始相交节点,以及如何使用迭代和递归两种方式原地反转单链表。内容包含完整的可运行代码、逻辑图解说明及易错点分析。

查找单链表相交的起始节点

给定两个单链表的头节点 headA 和 headB,目标是找出它们相交的起始节点。如果两个链表没有交点,则返回 nullptr。需要明确的是,这里的“相交”指的是指针地址相同(即内存中的同一个节点),而非仅仅是节点存储的数值相等。

思路解析

解决此问题的关键在于利用链表尾部对齐的特性。假设两个链表在相遇前分别有不同的长度,如果我们将较长的链表向前移动,直到剩余长度与短链表一致,那么两个链表尾部的长度就完全相同了。此时,两个指针同步向后遍历,首次相遇的位置即为相交起始点。

具体步骤如下:

  1. 遍历两个链表,分别计算它们的总长度 lenA 和 lenB。
  2. 定义两个指针 curA 和 curB 重新指向各自链表的头部。
  3. 比较长度,若 lenA 大于 lenB,让 curA 先向后移动 lenA - lenB 步;反之则让 curB 移动。这一步确保了两个指针距离链表尾部的距离相等。
  4. 两个指针同时向后移动,每次一步。当 curA == curB 时,返回该节点;若遍历结束仍未相遇,则返回 nullptr。

经过上述长度差的调整,两个指针进入了相同的“相对位置”状态,如图示,此时同步推进即可精准定位交点。

C++ 代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0;
        int lenB = 0;

        // 1. 计算链表A的长度
        while(curA != nullptr){ 
            lenA++;
            curA = curA->next;
        }
        // 2. 计算链表B的长度
        while(curB != nullptr){ 
            lenB++;
            curB = curB->next;
        }
        
        // 重置指针至头节点
        curA = headA;
        curB = headB; 
        
        // 3. 确保 curA 指向较长的链表,方便后续统一处理
        if(lenA < lenB){  
            swap(lenA, lenB);
            swap(curA, curB);
        }
        
        // 4. 计算长度差值,并移动长链表指针
        int gap = lenA - lenB; 
        while(gap){     
            gap--;
            curA = curA->next;  
        }
        
        // 5. 同步遍历,寻找交点
        while(lenB){   
            if(curA == curB)
                return curA; // 直接返回节点指针
            curA = curA->next;
            curB = curB->next;
            lenB--;
        } 
        return nullptr;  // 无交点
    }
};

反转单链表

给定单链表的头节点 head,要求将其反转并返回新的头节点。例如,输入 [1,2,3,4,5],输出应为 [5,4,3,2,1]。

迭代法(双指针/三指针)

迭代法是空间复杂度最优解(O(1)),核心思想是通过三个指针动态修改节点的 next 指向,使其指向前一个节点。

操作步骤:

  1. 判空:如果链表为空,直接返回 nullptr。
  2. 初始化指针:
    • cur 指向当前正在处理的节点,初始为 head。
    • per (previous) 指向前一个节点,初始为 nullptr(因为新头节点的 next 将是 null)。
    • temp 作为临时变量,用于保存 cur 的下一个节点,防止断链后无法继续遍历。
  3. 循环遍历:当 cur 不为空时:
    • 用 temp 保存 cur->next。
    • 将 cur->next 指向 per,完成局部反转。
    • per 前进一步,移动到 cur 的位置。
    • cur 前进一步,移动到 temp 的位置。
  4. 返回结果:循环结束时,cur 为 null,per 指向原链表的最后一个节点,即新链表的头节点,返回 per。
/**
 * 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* reverseList(ListNode* head) {
        if(head == nullptr)  // 处理空链表情况
            return nullptr;
            
        ListNode* per = nullptr; // 前驱节点,初始为空
        ListNode* cur = head;    // 当前节点
        ListNode* temp;          // 临时节点
        
        while(cur){              // 当当前节点不为空时执行
            temp = cur->next;    // 1. 暂存下一个节点,防止断链
            cur->next = per;     // 2. 核心反转:当前节点指向前驱
            per = cur;           // 3. 前驱指针右移
            cur = temp;          // 4. 当前指针右移
        }
        return per;              // 返回新的头节点
    }
};

递归法

递归法利用系统栈隐式维护路径,代码更简洁,但空间复杂度为 O(N)。主要思路是递归到链表末尾,然后在回溯过程中修改指向。

为了便于理解,可以封装一个内部递归函数 reverse(per, cur):

  • 终止条件:当 cur 为 null 时,说明已经处理完了所有节点,返回此时的 per(即新的头节点)。
  • 递归过程:
    - 保存 cur 的下一个节点到 temp。 - 反转当前指向:让 cur->next 指向 per。 - 递归调用:以 cur 为新的前驱,temp 为新的当前节点进行下一步。
/**
 * 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 {
private:
    // 辅助递归函数
    ListNode* reverse(ListNode* per, ListNode* cur) { 
        if(cur == nullptr)  // 到达原链表尾部
            return per;
        
        ListNode* temp = cur->next; // 保存后继
        cur->next = per;            // 反转指向
        return reverse(cur, temp);  // 递归处理下一段
    }

public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr) 
            return nullptr; 
        return reverse(NULL, head); // 初始前驱为空,当前为头节点
    }
};

以上就是C++实现相交链表检测与反转链表的详细内容,更多关于C++链表算法优化的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。