为什么说递归是码农的一道分水岭?

STC15单片机双串口通信实战:串口2配置与多设备交互 本文详细介绍了STC15单片机双串口通信的实战配置,重点解析串口2的硬件连接、寄存器设置及多设备交互实现。通过实际项目案例和完整代码示例,帮助开发者快速掌握STC15串口2的配置技巧,解决常见通信问题,提升嵌入式系统开发效率。 阅读详情

为什么这一篇要先写递归这种思想呢?初衷主要是因为最近在写设计模式中的组合模式。这个设计模式的实现呢,需要使用到树形数据结构,而树形结构又是天生的递归结构,所以这一篇主要是给大家打基础,顺便也从个人的一些开发经历来给大家安利一波递归。不然的话,读者后面很难看懂我后面要发的c语言设计模式--组合模式这篇文章。

递归在码农界有这么一种说法,人理解迭代,神理解递归。在我看来,递归确实应该算是码农编程能力的一道分水岭。所谓分水岭,就是说能轻松理解递归而且灵活运用的程序员往往思维方式是异于常人的(大部分情况也优于常人),这样子的程序员在本质上跟不能理解递归、甚至厌恶递归的程序员其实不是同一个level的开发者了。大家先别急着喷我,我有以下几点理由:

  • 不能理解递归,意味着归并、快排、二叉树、回溯、贪心、动态规划等人类花了几十数百年总结出来的这些优秀算法,对你而言只是个躺在书本上毫无价值的死代码。

  • 不能理解递归,意味着编译原理的词法分析、语法分析等,你将一无所知。虽然大部分人都没机会接触编译器底层机制,但是天天使用着各种各样的编译器,却对它内部一无所知,是个小遗憾。

  • 不能理解递归,意味着在大规模复杂情景下的开发,不得不忍受迭代的繁琐,以及无比臃肿丑陋的代码。

不过递归并不是万能的,要全面地认识它的优缺点。那就是递归实现的程序,虽然结构清晰、思路明了,但是递归的执行过程蛮让人费解的。人一旦陷进去递归的细节很容易就会被绕晕。递归程序的调试也很不方便,尤其在嵌入式设备等内存资源紧张的场合,容易发生堆栈溢出。

递归的哲学

那么递归是什么呢?我们的老祖宗其实在几千年前就已经告诉我们了。<<大学>>有曰:

古之欲明明德于天下者,

先治其国;

欲治其国者,先齐其家;

欲齐其家者,先修其身;

欲修其身者,先正其心;

欲正其心者,先诚其意;

欲诚其意者,先致其知,

致知在格物。

物格而后知至,知至而后意诚,

意诚而后心正,心正而后身修,

身修而后家齐,家齐而后国治,

国治而后天下平。

简单翻译一下这段话,主要意思是说:

古时候,要想使天下人都发扬光明正大的德行,就要先治好自己的国家;想要先治好自己的国家,就要先管理好自己的家庭;要想管理好自己的家庭,就要先修养自己的身心;要修养自己的身心,就要先端正自己的心志;要想端正自己的心志,就要先使自己的意念真诚,就要先丰富自己的知识;要想丰富自己的知识,就得深入研究事物的原理。

”

通过对万事万物的认识,研究后才能获得知识;获得知识后意念才能真诚;意念真诚后心思才能端正;心思端正后才能修养品性;品性修养后才能管理好家庭和家族;管理好家庭和家族后才能治理好国家;治理好国家后天下才能太平。

”

这段翻译完美地描述了递归的哲学,那就是要先达成一个大目标,必须先逐步把它分解成小目标,直到小目标是自己能够达到的为止。然后通过不断地达成小目标,最终实现大目标。

理解递归的关键

谨记递归的两个过程

以下是引用知乎网友的一段描述,讲得非常形象易懂:

递归是静中有动,有去有回。
循环是动静如一,有去无回。

”

举个例子,给你一把钥匙,你站在门前面,问你用这把钥匙能打开几扇门。

递归:你打开面前这扇门,看到屋里面还有一扇门(这门可能跟前面打开的门一样大小(静),也可能门小了些(动)),你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门,你继续打开,。。。, 若干次之后,你打开面前一扇门,发现只有一间屋子,没有门了。你开始原路返回,每走回一间屋子,你数一次,走到入口的时候,你可以回答出你到底用这钥匙开了几扇门。

循环:你打开面前这扇门,看到屋里面还有一扇门,(这门可能跟前面打开的门一样大小(静),也可能门小了些(动)),你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门,(前面门如果一样,这门也是一样,第二扇门如果相比第一扇门变小了,这扇门也比第二扇门变小了(动静如一,要么没有变化,要么同样的变化)),你继续打开这扇门,。。。,一直这样走下去。入口处的人始终等不到你回去告诉他答案。

递归思想递归就是有去(递去)有回(归来)。具体来说,为什么可以”有去“?这要求递归的问题需要是可以用同样的解题思路来回答类似但略有不同的问题(上面例子中的那一把钥匙可以开后面门上的锁)。为什么可以”有回“?这要求这些问题不断从大到小,从近及远的过程中,会有一个终点,一个临界点,一个baseline,一个你到了那个点就不用再往更小,更远的地方走下去的点,然后从那个点开始,原路返回到原点。

一个例子

我们来看下最简单的递归--阶乘算法,这个例子的巧妙解析也是出自知乎网友。

int f(int n)
{
    int sum = 0;
    if (0 == n)
        return 1;
    else
        sum = n * f(n-1);
    return sum;
}

这里面用f函数调用了自己,这该怎么理解?
我们先来直接展开一个计算结果看看:

f(4)=>4*f(3)
f(4)=>4*(3*f(2))
f(4)=>4*(3*(2*f(1)))
f(4)=>4*(3*(2*(1*f(0))))
f(4)=>4*(3*(2*1))
f(4)=>4*(3*2)
f(4)=>4*6
f(4)=>24

这里面非常清晰地展示了递归的过程,如下图:

这个例子就是非常典型的,在归来的过程中解决问题。

我们思考一下:

为什么在归来过程可以解决问题?

这是因为我们先寻找到了最小的目标,这个最小目标是我们可以直接完成的(也就是递归的终止条件)。等实现了最小的目标后,接着再逐级反过来实现更大的目标。直到完成我们最初定下的大目标为止。

到这里真的不得不感概,书中自由颜如玉、书中自有黄金屋。古人诚不欺我矣!

按照这样子的思路,可以总结出归来过程解决问题的递归模型:

 function recursion(大规模){
    if (end_condition){      // 明确的递归终止条件
        end;   // 简单情景
    }else{            // 先将问题全部描述展开,再由尽头“返回”依次解决每步中剩余部分的问题
        recursion(小规模);     // 递去
        solve;                // 归来
    }
}

因此只要在递归抓住最小目标是什么,以及思考怎么由最小目标反过来逐步实现更大的目标(其实就是在归来过程,怎么解决当前的问题),那么对于大部分的递归算法你就能不再畏惧,理解起来也不再吃力了。

类似更复杂的多重递归(比如汉诺塔、树的遍历等等),也可以套用这种思想,只要脑海中清晰地知道多种递归,不是进行一次目标分解,而是进行多次目标分解,理解起来也会容易很多。

有了递归的基础,就能进一步学习树形数据结构了。把树形数据结构学完了,才有可能学习理解设计模式中的组合模式。

群晖NAS搭建Git Server避坑指南:从SSH配置到权限管理的完整流程 本文提供了一份详尽的群晖NAS搭建Git Server实战指南。文章从启用并安全配置SSH服务入手,深入解析了用户权限体系设计、SSH连接与仓库初始化、客户端SSH密钥配置等核心步骤,并提供了常见错误排查与生产环境加固方案,帮助开发者成功构建私有、安全的代码托管平台。 阅读详情

相关推荐

MiniMax H3本地部署与ComfyUI集成实战:从环境配置到提示词优化

文本到视频生成是AI内容创作领域的关键技术,它基于扩散模型等深度学习原理,将自然语言描述转化为连贯的动态视觉序列。这项技术的核心价值在于大幅降低了视频制作的门槛,为短视频创作、概念可视化、教育内容生成等场景提供了高效工具。在实际工程实践中,成功部署和运行此类模型,如近期备受关注的MiniMax H3,需要精准处理环境配置、显存优化和提示词工程等环节。其中,解决“CUDA error: no kernel image is available”等版本兼容性问题,以及针对“8G显存”等有限资源进行参数调优,是确

weixin_33674976的博客 479

树形结构数据递归方法

每日一练

lgp199881的博客 430

【RViz2】导入urdf模型时报错:Could not load resource xxx,Unable to open file xxx,Error retrieving file xxx

初学ROS2,想要在RViz2中显示urdf模型。其中.urdf文件引用了外部的meshes文件夹。

qq_43557907的博客 9488

树型结构的遍历

 树型结构遍历 作者:郭宝利  来源:原创  日期:2004.06.27  树型结构的遍历通常使用递归程序来实现,所以本节给出一个按照内容查找,对树型结构进行遍历,如果和要查找的内容相等,则返回该节点的Handle。函数如下:/*---------------------------------------

MakeToday的专栏 1497

第四章 自定义组件、动画

第三章 自定义组件、动画 (一)自定义View 1.1) onMeasure:对当前View的尺寸进行测量 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) widthMeasureSpec和heightMeasureSpec包含测量模式和尺寸大小 int widthMode = MeasureSpec....

Stay Hungry Stay Foolish 求知若饥 虚心若愚 8133

Verilog仿真必备:FSDB dump命令全解析与实战配置指南

本文深入解析了Verilog仿真中FSDB波形记录的核心命令与实战配置技巧。针对大规模SoC验证场景,详细介绍了如何通过$fsdbDumpvars、$fsdbDumpfile等命令实现信号精准捕获、文件体积控制和动态启停,并提供了智能化的分层dump策略,帮助工程师在保证调试信息完整性的同时,大幅提升验证效率并有效管理波形数据。

cnn8visionary的博客 349

JS树形数据常用递归方法总结

在使用element ui的tree组建的时候经常需要对tree进行递归操作,去获取树形数据中的某些值,下面总结了常用的一些方法。

lishuaihao的博客 7990

YOLOv8【第十章:多任务扩展深度篇·第18节】不规则工业缺陷分割——针对划痕、裂纹的 Seg 模型调优!

🏆 本文收录于 《YOLOv8实战:从入门到深度优化》 专栏。该专栏系统复现并梳理全网各类 YOLOv8 改进与实战案例(当前已覆盖分类 / 检测 / 分割 / 追踪 / 关键点 / OBB 检测等方向),坚持持续更新 + 深度解析,质量分长期稳定在 97 分以上,可视为当前市面上 覆盖较全、更新较快、实战导向极强 的 YOLO 改进系列内容之一。

**My Coding Family** 3982

处理常见的树形结构的递归方法

后台设计一张分类表的时候,如果有多级分类,通常会这样设计,使用parentId来标注它的父级是哪条数据,而且这种分类往往是不确定多少级: 这种数据,对于后端来说只是一条条数据,而对于前端来说,必须把这样的数据转化为树形数据,此时可以使用递归方法类解决此类问题: 后端传过来的数据: 最终的转化的数据格式如下: 递归算法: function toArrayTree(array, parentId) { if(!Array.isArray(array)) { return [];

记录点滴 4515

Clawdbot安装教程:从零开始到接入飞书

这几天,Clawdbot把整个科技圈都刷屏了。就是这个胖逼小龙虾🦞。不过现在改名叫Moltbot了。原因很简单:被Anthropic告了。Anthropic觉得Clawdbot这名字太像Claude Code的延伸产品,要求改名。真的,Anthropic你这家伙…更离谱的是,因为Clawdbot太火,Mac Mini都被抢断货了。无数人为了用它,疯狂买Mac Mini。我刚打开美团外卖,发现居然没货了???

Maynor的博客 2179

MTK(基础篇)ROM烧录以及分区的作用

本文介绍了MTK芯片设备的刷机流程及关键分区功能。首先通过MTK烧录工具加载ROM文件(包括引导文件和分区表),重点解析了各分区的核心作用:preloader类似BIOS负责硬件初始化;lk作为二级引导程序加载内核;vbmeta验证系统完整性;boot包含Linux内核;dtbo调整硬件配置;modem管理通信功能;tee保护生物识别数据;system/vendor分别存放系统核心和硬件驱动。特别指出preloader、vbmeta等关键分区损坏会导致设备变砖,而recovery分区是重要的救砖入口。全文简

weixin_49303682的博客 444

C语言之二叉查找树

对于树的基本认识,我们很容易通过我们平常所见到的树来理解:一棵树,有一个根,根往上又会分叉出大树枝,大树枝又会分叉出小树枝,以此往复,直到最后是叶子。而作为数据结构的树也是类似的,只不过我们通常将它倒着画。树的应用也相当广泛,例如在文件系统,数据库索引中的应用等。本文会对树的基本概念做介绍,但重点介绍二叉查找树。 软件是通过数据和算法实现对现实世界的抽象,具有层次关系的数据在现实世界中能找到很多实例,比如: 公司组织架构:董事长-CXO-总监-经理-主管-员工; 中国行政区域划分:中国-省-市(县)-.

Jiangtagong的博客 1160

自然语言处理在智能客服系统中的应用

引言与背景 1.1 书籍的目的和内容概述 《自然语言处理在智能客服系统中的应用》旨在探讨自然语言处理(NLP)技术在智能客服系统中的应用,帮助读者理解NLP的核心概念及其在解决实际业务问题中的关键作用。随着人工智能技术的快速发展,自然语言处理成为构建智能客服系统的核心模块之一。本书将深入解析NLP

AI天才研究院 969

树形结构递归_为什么说递归是码农的一道分水岭?

为什么这一篇要先写递归这种思想呢?初衷主要是因为最近在写设计模式中的组合模式。这个设计模式的实现呢,需要使用到树形数据结构,而树形结构又是天生的递归结构,所以这一篇主要是给大家打基础,顺便也从个人的一些开发经历来给大家安利一波递归。不然的话,读者后面很难看懂我后面要发的c语言设计模式--组合模式这篇文章。递归在码农界有这么一种说法,人理解迭代,神理解递归。在我看来,递归确实应该算是码农编...

weixin_28785069的博客 330

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

揭秘培训机构的 C/C++ 的谎言:为什么不学汇编,你永远只能当“门外汉”?

不要被“速成”的营销蒙蔽。C/C++ 是一把直插硬件心脏的利剑,而汇编语言就是这把剑的握柄。你可以不手写汇编(毕竟效率低),但你必须能读懂汇编。这条路很难,很慢,没有捷径。但请相信,当你掌握汇编视角的那一刻,你眼中的 C++ 代码将不再是枯燥的字符,而是流动的、透明的、完全受你掌控的比特洪流。那才是真正的自由。

抟土成人祖,炼石补青天。眼中览银河,手可摘星辰。 573

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Python文件操作与异常处理:从能跑通到可交付的工程分水岭

文件操作和异常处理是Python工程化落地的核心基础能力,本质是管理操作系统资源生命周期与构建可控失败路径。理解open()背后的缓冲区、句柄、编码机制,掌握pathlib跨平台路径处理、utf-8-sig/BOM兼容方案,以及try-except分层捕获(业务层精确匹配+入口点宽泛兜底)、异常链raise ... from ...、结构化logging等关键技术,直接决定程序在真实环境中的健壮性与可维护性。本文聚焦生产级实践,覆盖路径陷阱、中文乱码根治、大文件性能优化及配置自愈系统实现。

weixin_30572613的博客 326

我们为什么要思考算法???

源头 “算法”的中文最早出现在中国汉代的数学名著《周髀算经》中。《周髀算经》卷上有:“数之法出于圆方。圆出于方,方出于矩。矩出于九九八十一”。意思是: 算数的方法都出于对圆、对方的计算,其中圆出于方(圆形面积=外接正方形x圆周率/4),方出于矩(正方形源自两边相等的矩),矩的计算出于九九八十一 (长乘宽面积的计算依自九九乘法表)。追溯回去,在春秋战国时代,《九九乘法歌诀》已经开始

u010887500的专栏 497

Java面试手撕代码的高频题型与思路

动态规划是手撕代码的终极Boss,面试官通常用它来拉开差距。背包问题、最长公共子序列、最长递增子序列、打家劫舍、爬楼梯变种。动态规划不要一上来就写代码,先画出状态转移表。比如“0-1背包”:二维dp[i][j]表示前i个物品容量为j时的最大价值;转移方程dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+v[i])。注意初始化和边界:dp[0][j]=0,dp[i][0]=0。进阶考点是状态压缩:用一维数组倒序更新,空间复杂度从O(nW)降到O(W)。

qq_35974860的博客 40

算法基石:一本大学的全面算法课程知识体系与学习心法

《算法学习指南:从基础到精通的系统路径》摘要:本文系统介绍了算法学习的核心价值与知识体系。算法作为计算思维的基石,是区分工程师能力的关键标尺,决定了代码效率与优雅程度。文章详细解析了时间复杂度、数据结构(数组/链表/哈希表)、五大核心算法思想(分治/动态规划/贪心/回溯/搜索),并提供了Python代码示例。针对大学生学习算法,提出了"理论+实践+专项训练"的心法,推荐通过LeetCode按主题刷题、建立错题本、尝试一题多解来提升能力。文中推荐了《算法导论》等经典教材和MIT在线课程资源

2403_88882317的博客 970

c语言也能用模板方法模式?

模式动机在嵌入式的应用场景中,管理资源(例如文件、内存)是一件非常麻烦、非常容易出错的事情。因为在分配资源后,还必须释放资源。例如fopen()打开文件后,必须要使用fclose()来关...

qq_35579835的博客 697

C++模板进阶:从SFINAE到概念约束的实战应用

模板元编程是C++中一种在编译期进行计算和类型推导的编程范式,其核心价值在于将运行时工作转移到编译期,从而生成更高效、更定制化的代码。通过类型推导、SFINAE(替换失败并非错误)等机制,编译器能够在编译阶段进行智能决策,实现零成本抽象。这种技术在现代C++库开发、性能优化和代码泛化中具有重要价值,特别是在构建通用容器、算法库和序列化框架等场景。本文以C++模板进阶为主题,深入探讨了SFINAE和变参模板等核心机制,并结合编译期字符串哈希等实战案例,展示了如何利用模板特性提升代码的灵活性与执行效率。

weixin_29895109的博客 256

c语言,去你的策略模式!

前言+这里先插一点题外话,在C语言中,实现封装、继承、隐藏、多态等等特性,是完全没有问题的。但是在使用过程中,必定是不如自带这些特性的语言方便好用的,比如C++\java等。一旦要通过C...

qq_35579835的博客 596

GESP C++认证全解析:从算法基础到备考策略

在编程学习与能力认证领域,掌握核心算法与数据结构是构建扎实技术功底的关键。算法作为解决问题的明确指令序列,其设计与分析能力直接决定了程序的效率与可靠性。数据结构则是高效组织与管理数据的基石,二者结合构成了计算思维的核心。从工程实践角度看,深入理解排序、查找、递归、动态规划等基础算法,以及数组、链表、栈、队列、树等经典数据结构,不仅能显著提升代码性能,更是通过系统性能力认证(如GESP C++等级考试)的必备技能。这些知识广泛应用于软件开发、竞赛编程、算法优化及解决大规模数据处理等实际场景。本文聚焦于GESP

weixin_31315567的博客 331

AI会取代IT从业者吗?

AI不会完全取代IT从业者,但会淘汰不善于利用AI的程序员。它作为高效助手能完成代码生成、调试辅助等任务,但缺乏抽象思维和创新能力,无法替代人类在系统设计、业务沟通等层面的作用。未来的竞争力取决于人机协作能力——善用AI处理重复工作,聚焦高价值决策。固守传统编码方式的人将面临淘汰,而掌握AI工具并深耕领域知识的开发者会成为稀缺人才。技术的进步始终在重塑职业,而非消灭职业,关键在于主动适应变革。

xiaoyezhiei的博客 884

嵌入式C语言开发必备:36种基础算法实战进阶指南

算法是计算机科学的核心基础,它通过定义明确的步骤来解决特定问题或执行计算。其原理在于将复杂任务分解为可控的操作序列,并通过时间与空间复杂度来衡量效率。掌握算法思维的技术价值在于,它能显著提升代码的执行效率、降低资源消耗,并增强程序的可靠性与可维护性。在嵌入式系统开发等资源受限的应用场景中,高效的算法直接关系到功耗、响应速度和内存占用。本文聚焦嵌入式C语言开发,深入解析冒泡排序、选择排序、二分查找、链表操作及斐波那契数列等高频基础算法,并结合**嵌入式场景**和**内存管理**等热词,提供从原理到代码实现的实

weixin_33795093的博客 484

C/C++全栈学习路径:从语言基础到系统编程与项目实战

C/C++作为系统级编程的核心语言,其学习路径需要从底层原理到高级应用逐步深入。理解计算机内存模型、指针机制和编译链接过程是掌握这门语言的基础,这直接关系到程序的性能和稳定性。面向对象编程和现代C++特性(如智能指针、移动语义)则提升了代码的安全性和表达力,其技术价值在于能够构建高效、可维护的大型软件系统。在系统编程层面,进程线程管理、网络Socket编程和性能优化技术是开发高性能服务器和底层应用的关键。这些知识最终会收敛到游戏开发、音视频处理、嵌入式等实际应用场景中。通过结合VSCode、GDB等工具链和

weixin_29266007的博客 231

心之所向,百炼成钢 第一章

20160709踏上扬州,20170826奔向武汉。在过去的1个半月实习前的培训中,有得有失。       在写这一篇文章的时候,我极力想摆脱实习报告的套路,想要言简意赅。少写一些空乏的琐事,多一些知识的干货。在经过扬州的1个半的培训中。我知道了自己的路,我不愿自己的未来随风随浪,漂浪东西,亲像船无港。       我是一名实习的java码农,但是我希望未来的我是XX产品的开发者。在过去扬州的培训中

cmazxiaoma的博客 672
上一篇: 一款GitHub开源的神器,非常好用!
下一篇: 好用到爆的 Java 技巧,不是吹嘘的!
编程IT圈
博客等级 码龄6年 1130粉丝 544原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值