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

C++ 递归算法详解:汉诺塔与链表操作

综述由AI生成阐述递归算法的核心思想,包括基本情况、递归情况及结果合并。通过汉诺塔、合并有序链表、反转链表及两两交换节点四个 C++ 实例,展示递归函数的设计与实现。文末总结了解决递归问题的关键经验,如明确终止条件、分解问题、参数管理及避免重复计算,有助于提升代码清晰性与可维护性。

涅槃凤凰发布于 2026/3/30更新于 2026/5/2431 浏览
C++ 递归算法详解:汉诺塔与链表操作

前言

递归是一种在算法中广泛应用的思想,其主体思想是通过将复杂的问题分解为更简单的子问题来求解。具体而言,递归通常包括以下几个要素:

  1. 基本情况(Base Case):每个递归算法必须有一个或多个基本情况,用于定义何时停止递归。基本情况是问题的 最小实例,直接返回结果,不再进行进一步的递归。
  2. 递归情况(Recursive Case):当问题不是 基本情况 时,递归算法会将问题 拆分成更小的子问题。算法会调用自身来解决这些子问题,通常会在调用中传递参数以反映问题的简化。
  3. 合并结果(Combining Results):在递归调用返回后,算法 会将子问题的结果合并,以得到原始问题的解。

递归的优势在于其代码通常更简洁且易于理解,尤其是在处理分治问题(如排序、搜索等)时。然而,递归也可能导致栈溢出问题,因为每次调用都会在栈上占用空间,因此在使用时需要考虑调用深度和性能优化。

以下是相关习题解析。

1. 汉诺塔(easy)

题目链接:汉诺塔

递归函数流程:

  1. 当前问题规模为 n=1 时,直接将 A 中的最上面盘子挪到 C 中并返回;
  2. 递归将 A 中最上面的 n-1 个盘子挪到 B 中;
  3. 将 A 中最上面的一个盘子挪到 C 中;
  4. 将 B 中上面 n-1 个盘子挪到 C 中。

解题思路:

  • 先把 n-1 盘 全部移到 B 上去
  • 再把 第 n 盘 移到 C 上去
  • 再把 n-1 盘移到 C 上去

代码如下:

class Solution {
public:
    void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {
        dfs(A, B, C, A.size());
    }
    
    void dfs(vector<int>& A, vector<int>& B, vector<int>& C, int n) {
        if (n == 1) {
            C.push_back(A.back());
            A.pop_back();
            return;
        }
        dfs(A, C, B, n - 1); // 这一步是为了将除了最大的盘子留下外,其他全部转移到 B 盘
        C.push_back(A.back());
        A.pop_back(); // 这一步是为了把最大的盘子转移到 C 盘
        dfs(B, A, C, n - 1); // 这一步是进行递归,B 盘变成了 A 盘,A 盘变成了 B 盘,目的是为了将其他盘全部转移到 C 盘
    }
};

2. 合并两个有序链表(easy)

题目链接:合并两个有序链表

题目描述:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

算法思路:

  1. 递归函数的含义:交给你两个链表的头结点,你帮我把它们合并起来,并且返回合并后的头结点;
  2. 函数体:选择两个头结点中较小的结点作为最终合并后的头结点,然后将剩下的链表交给递归函数去处理;
  3. 递归出口:当某一个链表为空的时候,返回另外一个链表。

注意:链表的题一定要画图,搞清楚指针的操作!

解题思路:

  • 判断某一个参数是否为空,为空则返回 另一个参数
  • 如果两者都不为空,则 比较 l1 的元素和 l2 元素的大小
  • 元素小的节点留下,并把 该节点的 next 和 另一节点 作为下一轮递归函数的参数
  • 下一轮递归函数的 返回值变为该节点的 next
  • 返回该节点 (小的那一个)
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        if (list1 == nullptr) {
            return list2;
        }
        if (list2 == nullptr) {
            return list1;
        }
        if (list1->val <= list2->val) {
            list1->next = mergeTwoLists(list1->next, list2);
            return list1;
        } else {
            list2->next = mergeTwoLists(list1, list2->next);
            return list2;
        }
    }
};

3. 反转链表(easy)

题目链接:反转链表

题目描述:

解题思路:

  • 先通过一层循环找到尾,因为 尾就是新的头节点
  • 找到尾之后,把 head 做为参数,传给递归函数

递归函数:

  • 如果 head->next 为空,直接返回 head
  • 否则,将 head->next 作为参数进入下一次递归
  • 下一次递归函数的返回值->next=head
  • head->next=nullptr
  • 返回 head
class Solution {
public:
    ListNode* reverseL(ListNode* head) {
        if (head->next == nullptr) return head;
        else {
            reverseL(head->next)->next = head;
            head->next = nullptr;
            return head;
        }
    }
    
    ListNode* reverseList(ListNode* head) {
        ListNode* it = head;
        if (head == nullptr) return head;
        while (it->next != nullptr) {
            it = it->next;
        }
        reverseL(head);
        return it;
    }
};

4. 两两交换链表中的节点(medium)

题目链接:两两交换链表中的节点

题目描述:

解题思路:

  • 如果(1)head 为空,返回 nullptr
  • 如果(2)head->next==nullptr,返回 head
  • 否则(3)将 head->next->next 作为参数进行下一次递归
  • 递归的返回值赋值给 head->next->next
  • 交换 head 和 head->next
  • 返回原来的 head->next
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if (head == nullptr) {
            return nullptr;
        } else if (head->next == nullptr) {
            return head;
        }
        head->next->next = swapPairs(head->next->next);
        ListNode* it = head->next;
        head->next = head->next->next;
        it->next = head; // 交换 head 和 head->next
        return it;
    }
};

结语

解决递归问题时,可以遵循以下经验:

  1. 明确基本情况:确保清楚地定义基本情况,以便在满足条件时能够正确终止递归。
  2. 分解问题:将问题有效地拆分为更小的子问题,确保每次递归调用都朝着基本情况逼近。
  3. 参数管理:仔细选择和管理递归调用中的参数,以便有效传递必要的信息并简化问题。
  4. 结果合并:清晰地规划如何合并子问题的结果,以构建最终解。
  5. 避免重复计算:对于具有重叠子问题的情况(如斐波那契数列),考虑使用记忆化或动态规划来优化性能。
  6. 可视化:在思考递归逻辑时,可以尝试绘制递归树,帮助理解调用过程和结果合并。
  7. 测试和验证:使用边界条件和基本情况测试递归实现,确保其正确性和稳定性。

通过遵循这些经验,可以更有效地解决递归问题,并提高代码的清晰性和可维护性。

目录

  1. 前言
  2. 1. 汉诺塔(easy)
  3. 2. 合并两个有序链表(easy)
  4. 3. 反转链表(easy)
  5. 4. 两两交换链表中的节点(medium)
  6. 结语
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 前端关系图组件 relation-graph 推荐与使用
  • 基于 Python 与 AI 的智能害虫识别助手
  • 本地离线部署 AI 大模型:Ollama + OpenClaw + Qwen3.5 实战指南
  • Ground Slow, Move Fast: Dual-System Foundation Model for VLN
  • 大型语言模型(LLMs)的训练原理与网络架构解析
  • LIBERO:终身机器人学习的综合基准测试平台
  • LLaMA-Factory 部署与大模型微调实战
  • 国内 AI 开发常用:HuggingFace 镜像站 hf-mirror.com 高效下载与避坑指南
  • Flask 框架从入门到实战完整指南
  • Python 数据分析入门:从环境搭建到建模实战指南
  • 大模型技术全景:架构、分类与核心应用场景
  • Python Django 协同过滤电影推荐系统设计
  • 程序员 Python 副业方向与接单实战建议
  • 异构算力下的通义万相 2.1 文生图技术部署与优势解析
  • 浙大与蚂蚁集团 KAG 框架:知识增强生成技术解析
  • 算法基础:前缀和原理与 Java 实现
  • Python 基于 OpenCV 的指纹识别系统实现
  • DeepSeek-R1-Distill-Llama-8B 深度解析:LoRA 微调、长上下文与 KV Cache 优化
  • AG-UI:构建 AI 前端交互的统一协议
  • MiniMax 海螺 AI 视频:图片与文本生成高质量视频

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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