跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

链表两数相加算法详解(C++ 实现)

介绍使用 C++ 解决链表两数相加问题的算法实现。通过逆序链表存储数字,模拟手工加法过程,利用虚拟头节点简化操作。核心步骤包括遍历链表、逐位求和、处理进位及内存管理。文章涵盖基础代码、空指针防护、动态内存释放技巧,并拓展了正序链表(栈实现)、大数相加及多链表合并场景。适合学习链表结构与 C++ 指针操作的开发者参考。

山野诗人发布于 2026/3/21更新于 2026/9/561 浏览

一、问题剖析:两数相加究竟是什么?

在数据结构场景下,两数相加通常指两个非空链表分别表示两个非负整数。链表中的每个节点只存储一位数字,且按逆序方式排列。任务是将这两个数相加,并以相同逆序的链表形式返回和。

例如:链表 1 为 2 -> 4 -> 3(代表 342),链表 2 为 5 -> 6 -> 4(代表 465)。相加结果为 807,对应返回链表应为 7 -> 0 -> 8。

采用逆序存储是为了方便从最低位(个位)开始进行加法操作,模拟手工计算过程,便于处理进位。

二、实现思路:一步步拆解问题

  1. 初始化相关变量 创建一个新的链表存储结果,使用虚拟头节点(哨兵节点)简化操作。定义指针指向当前新链表末尾,以及记录进位值的变量(初始为 0)。

  2. 遍历两个链表进行相加 同时遍历两个输入链表,获取当前节点值。若某链表已遍历结束,其当前节点值视为 0。将两值与进位值相加得到总和。

  3. 计算当前位数字和新的进位值 当前位数字为总和对 10 取余,新进位值为总和除以 10 取整。

  4. 添加新节点到结果链表 创建新节点存储当前位数字,添加到结果链表末尾,移动末尾指针。C++ 中需使用 new 动态分配内存。

  5. 处理链表遍历结束后的进位 若遍历结束后进位值不为 0,需在结果链表末尾新增节点存储该进位值。

  6. 返回结果链表 返回虚拟头节点的下一个节点作为结果链表的第一个有效节点。

三、代码实现:用 C++ 语言实战

#include <iostream>
using namespace std;

// 链表节点定义
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) {}
};

// 核心函数:两数相加
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    // 虚拟头节点
    ListNode* dummy = new ListNode(0);
    ListNode* cur = dummy;
    int carry = 0;

    // 只要有一个链表没遍历完,或还有进位,就继续算
    while (l1 != nullptr || l2 != nullptr || carry != 0) {
        int num1 = (l1 != nullptr) ? l1->val : 0;
        int num2 = (l2 != nullptr) ? l2->val : 0;
        int sum = num1 + num2 + carry;
        carry = sum / 10;
        int curVal = sum % 10;

        cur->next = new ListNode(curVal);
        cur = cur->next;

        if (l1 != nullptr) l1 = l1->next;
        if (l2 != nullptr) l2 = l2->next;
    }

    ListNode* result = dummy->next;
    delete dummy;
    return result;
}

// 辅助函数:打印链表
void printList(ListNode* head) {
    while (head != nullptr) {
        cout << head->val;
        if (head->next != nullptr) cout << " -> ";
        head = head->next;
    }
    cout << endl;
}

// 测试代码
int main() {
    // 构建链表 1:2 -> 4 -> 3
    ListNode* l1 = new ListNode(2);
    l1->next = new ListNode(4);
    l1->next->next = new ListNode(3);

    // 构建链表 2:5 -> 6 -> 4
    ListNode* l2 = new ListNode(5);
    l2->next = new ListNode(6);
    l2->next->next = new ListNode(4);

    // 计算并输出结果
    ListNode* res = addTwoNumbers(l1, l2);
    cout << "结果链表:";
    printList(res);

    // 释放内存
    delete l1->next->next; delete l1->next; delete l1;
    delete l2->next->next; delete l2->next; delete l2;
    delete res->next->next; delete res->next; delete res;

    return 0;
}

四、实战技巧与注意事项

1. 处理链表为空的情况(nullptr 判断)

C++11 及以后标准推荐使用 nullptr。在核心函数中,若链表遍历到末尾(指针为 nullptr),将当前值视为 0 参与计算,避免直接访问触发空指针崩溃。

2. 进位的处理要彻底

进位是链表加法最容易出错的点。不仅遍历过程中要传递进位,遍历结束后若进位不为 0,必须新增节点存储。循环条件应包含 carry != 0。

3. 虚拟头节点的使用

使用 dummy 节点可简化逻辑,无需判断结果链表是否为空。所有新节点统一挂在 cur->next 上,最后返回 dummy->next。注意手动释放虚拟头节点内存。

4. C++ 动态内存管理

C++ 没有自动垃圾回收,new 创建的对象必须手动 delete。建议封装 freeList 辅助函数批量释放,或从链表末尾往前删以避免内存泄漏。

5. 构造函数的合理使用

结构体定义多个构造函数可避免冗余代码,如 new ListNode(5) 即可初始化值和 next 指针。

6. 代码可读性与规范性
  • 指针命名见名知意(如 cur, dummy)。
  • 遵循 C++ 规范,* 紧跟类型。
  • 关键逻辑添加注释。

五、拓展与进阶

1. 链表存储数字为正序

若链表正序存储(如 3→4→2 代表 342),无法直接从表头加。可借助 C++ stack 容器,将节点值压入栈,利用栈顶为最低位的特性模拟逆序相加。

2. 处理大数相加

当数字超出 int 或 long long 范围时,链表是最优解。每个节点只存 0-9 的单个数字,逐位相加无需担心溢出。

3. 多链表相加

若需 3 个及以上链表相加,可将链表指针存入 vector<ListNode*>,遍历容器获取每一位值,避免重复写多个 if 判断。

4. 智能指针避免内存泄漏

可使用 C++11 智能指针 shared_ptr/unique_ptr 自动管理内存,降低内存泄漏风险。

六、总结

链表两数相加不仅是数据结构题,更是 C++ 核心语法的综合练习:

  • 数据结构层面:掌握链表遍历、节点创建/连接、进位传递。
  • C++ 语法层面:吃透指针操作、动态内存管理、结构体构造函数、容器和智能指针的使用。

建议初学者先跑通基础代码,修改测试案例验证逻辑,再尝试封装内存释放函数及实现正序链表相加。

目录

  1. 一、问题剖析:两数相加究竟是什么?
  2. 二、实现思路:一步步拆解问题
  3. 三、代码实现:用 C++ 语言实战
  4. 四、实战技巧与注意事项
  5. 1. 处理链表为空的情况(nullptr 判断)
  6. 2. 进位的处理要彻底
  7. 3. 虚拟头节点的使用
  8. 4. C++ 动态内存管理
  9. 5. 构造函数的合理使用
  10. 6. 代码可读性与规范性
  11. 五、拓展与进阶
  12. 1. 链表存储数字为正序
  13. 2. 处理大数相加
  14. 3. 多链表相加
  15. 4. 智能指针避免内存泄漏
  16. 六、总结

更多推荐文章

查看全部
  • pxcharts-vue:基于 Vue3 的开源多维表格解决方案
  • 自然语言处理在医疗领域的应用与实战
  • 四款主流 AI 编程 IDE 横向评测:从辅助到代理的演进路径
  • LLM 项目实战:使用 LLaMA-Factory 进行 DPO 训练
  • 30 天 CTF 入门:Web 与杂项速成计划
  • 渗透测试全流程解析与常见 Web 漏洞防护
  • DeepSeek 使用指南:提示词技巧与本地知识库搭建
  • 动态规划基础:状态表示与转移方程解析
  • Ubuntu 系统下 Python 连接金仓 KingbaseES 数据库实现增删改查
  • 基于 Servlet 的美食分享网站设计与实现
  • 从销售助理转行软件测试:零经验求职与学习路径分享
  • C++ mio 库内存映射文件 IO 使用指南
  • SpringBoot Java 银行排队叫号系统
  • 新手如何从零开始学习漏洞挖掘
  • JavaScript Proxy 代理机制与核心方法详解

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online