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

递归算法实战:汉诺塔与合并有序链表

递归算法的核心在于宏观视角,相信函数功能而非陷入细节展开。通过汉诺塔与合并有序链表两个经典案例,演示如何利用递归简化问题规模。重点讲解递归终止条件的设计以及状态转移逻辑,帮助建立清晰的递归思维模型,消除对递归调用的恐惧感,掌握 C++ 中递归函数的实际编写技巧。

星星泡饭发布于 2026/3/27更新于 2026/10/1994 浏览
递归算法实战:汉诺塔与合并有序链表

递归算法实战:汉诺塔与合并有序链表

递归往往是初学者感到最棘手的概念之一。很多人看到函数调用自己时会产生畏惧感,觉得无法追踪执行流程。其实,理解递归的关键在于建立'宏观视角'——不要纠结于函数内部每一层的细节展开,而是信任当前函数的功能定义。只要明确函数要完成什么任务,并设计好递归终止条件,剩下的交给递归本身即可。

递归的核心思维:宏观视角

看待递归最重要的点,是清楚这个函数的功能到底是什么。递归的本质是自己调用自己,就像我们调用普通函数一样,目的是利用其功能。

以归并排序为例,mergesort 的功能是将无序数组变为有序。实现时,我们将数组分为左右两部分,分别调用 mergesort 让两边有序,最后合并。这里不需要关心左边具体怎么排好的,只需要相信调用 mergesort(left) 后,左边就已经有序了。同理,右边也是如此。

这种思维方式能避免陷入无限递归的细节泥潭。写递归时,只需关注两点:

  1. 递归结束条件:保证有出口,通常是问题规模缩小到最小单位。
  2. 功能假设:假设子问题已被解决,专注于当前层如何组合结果。

下面通过两个经典题目来实践这一思路。

1. 汉诺塔

题目描述

有三根柱子 A、B、C。A 柱上有 n 个大小不同的圆盘,从小到大叠放。要求将所有盘子从 A 移动到 C,过程中大盘不能压在小盘上,且每次只能移动一个盘子。

解题思路

这是一个典型的分治问题。

  • 基础情况:如果只有 1 个盘子,直接从 A 移到 C。
  • 递归步骤:对于 n 个盘子:
    1. 将上面的 n-1 个盘子从 A 借助 C 移到 B。
    2. 将第 n 个(最大的)盘子从 A 直接移到 C。
    3. 将 B 上的 n-1 个盘子借助 A 移到 C。

关键在于步骤 1 和 3,它们本质上是同一个问题的缩小版。

C++ 代码实现
class Solution {
public:
    void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {
        dfs(A, B, C, A.size());
    }

private:
    void dfs(vector<int>& x, vector<int>& y, vector<int>& z, int n) {
        // 递归结束条件:只剩一个盘子,直接移动
        if (n == 1) {
            z.(x.());
            x.();
            ;
        }
        
        
        (x, z, y, n - );
        
        
        z.(x.());
        x.();
        
        
        (y, x, z, n - );
    }
};
push_back
back
pop_back
return
// 1. 将 n-1 个盘子从 x 移到 y (借助 z)
dfs
1
// 2. 将最大的盘子从 x 移到 z
push_back
back
pop_back
// 3. 将 n-1 个盘子从 y 移到 z (借助 x)
dfs
1

2. 合并两个有序链表

题目描述

给定两个升序链表,将它们合并成一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

解题思路

利用递归处理链表的头结点比较:

  1. 递归含义:函数接收两个链表头结点,返回合并后的头结点。
  2. 选择逻辑:比较两个头结点的值,较小的那个作为当前合并链表的头,它的 next 指针指向剩余部分的合并结果。
  3. 递归出口:当其中一个链表为空时,直接返回另一个链表。

注意:链表操作务必画图理清指针指向,递归中要注意不要丢失引用。

C++ 代码实现
/**
 * 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* mergeTwoLists(ListNode* list1, ListNode* list2) {
        // 递归结束条件:若某链表为空,返回另一链表
        if (list1 == nullptr) {
            return list2;
        }
        if (list2 == nullptr) {
            return list1;
        }

        // 选择较小的头结点,并递归处理剩余部分
        if (list1->val > list2->val) {
            // list2 更小,将其 next 指向剩余部分的合并结果
            list2->next = mergeTwoLists(list1, list2->next);
            return list2;
        } else {
            // list1 更小,将其 next 指向剩余部分的合并结果
            list1->next = mergeTwoLists(list1->next, list2);
            return list1;
        }
    }
};

总结

递归不是魔法,而是一种解决问题的策略。通过汉诺塔和链表合并的例子可以看出,只要抓住'问题分解'和'信任子问题'这两个核心,就能写出简洁高效的递归代码。在实际开发中,遇到复杂结构问题时,不妨先尝试用递归拆解,往往能获得更优雅的解法。

目录

  1. 递归算法实战:汉诺塔与合并有序链表
  2. 递归的核心思维:宏观视角
  3. 1. 汉诺塔
  4. 题目描述
  5. 解题思路
  6. C++ 代码实现
  7. 2. 合并两个有序链表
  8. 题目描述
  9. 解题思路
  10. C++ 代码实现
  11. 总结

更多推荐文章

查看全部
  • MySQL 架构与执行原理详解
  • OpenClaw 生态:16 款 AI Agent 选型指南
  • 2024 大模型学习路线:从零基础到精通的系统指南
  • Flutter 三方库 flutter_google_maps_webservices 鸿蒙化适配指南
  • 医疗 AI 中的模型融合与集成策略实战
  • OpenTiny NEXT 前端智能化:AI 前端与 WebAgent 系统学习指南
  • Llama-Factory 打造大模型定制化流水线
  • 无人机地面站实战进阶:飞行控制指南
  • Vivado 安装指南:从官网下载至完成安装
  • 前端错误处理最佳实践与策略
  • FPGA 摄像头采集处理显示指南:OV5640 到 HDMI 实时显示
  • Win10 升级后 365 Copilot 弹窗频发?彻底禁用与关闭方案
  • Python 基础:Jupyter Notebook 实战与优势介绍
  • 人脸识别核心算法:FaceNet 与 ArcFace 原理及实战
  • 位运算实战:两数之和、唯一数字与消失数字解析
  • 机器人灵巧手(Dexterous Hand)顶会论文精选 RSS CoRL ICRA IROS
  • Rokid JSAR 基于 Web 技术栈的 AR 开发环境搭建与 3D 时钟实战
  • Flutter 三方库 eth_sig_util 的鸿蒙化适配指南
  • OSGEarth 在 Qt C++ 中显示三维地球经纬度
  • 基于 LLM、RAG 与指令微调构建智能体的方法

相关免费在线工具

  • 加密/解密文本

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