递归三种分类方法

文章目录

递归是编程语言中常见的算法技巧,但是递归名称很多,我整理了一下递归常见的三种分类法。

按调用"路数"分(最常见)

这是根据一个函数在递归时,会派生出几个"分身"来分类的。

A. 线性递归 (Linear Recursion)

  • 特点 :函数在递归阶段,只调用一次自己。
  • 长相
clike 复制代码
void linear(int n) {
    if (n <= 0) return;
    // 只调用一次自己
    linear(n - 1);
}
  • 理解 :这就像是一个单向链表,或者一根绳子,一头拉着一头,直到拉断(触底反弹)。
  • 例子:计算阶乘、遍历单链表。
  • 优化:这种递归可以直接改成循环!

B. 树形递归 (Tree Recursion)

*  特点 :函数在递归阶段,调用了多次 (通常是两次或以上)自己。

*  长相

clike 复制代码
void tree(int n) {
    if (n <= 1) return;
    // 调用两次自己,这就分叉了!
    tree(n - 1);
    tree(n - 2); 
}
  • 理解:这就像是二叉树的遍历,每走一步就分两叉,呈指数级爆炸增长。
  • 例子:斐波那契数列(朴素写法)、二叉树遍历。
  • 优化:这种递归有两种优化方案,使用显式栈(避免系统栈溢出)和记忆化搜索(加缓存)。但是要视情况而定:显式栈代码复杂;而多线程环境里的fork/join用的树形递归往往是拆分数据集,几乎没有重复的入参,加缓存没有用。

按"谁调用谁"分

这是根据函数调用的"人际关系"来分类的。

A. 直接递归 (Direct Recursion)

  • 特点 :函数 A 直接调用 自己(A)
  • 长相
clike 复制代码
void A() { 
    // ... 
    A(); // 我直接call我自己
}
  • 备注:这是我们最最常用的递归方式。

B. 间接递归 (Indirect Recursion)

  • 特点 :函数 A 调用函数 B ,函数 B 又反过来调用函数 A
  • 长相
clike 复制代码
void A() { 
    // ...
    B(); // 我让兄弟帮我干
}
    
void B() {
    // ...
    A(); // 兄弟又把活扔回给我
}
  • 理解:这就像是两个人互相踢皮球,直到把球踢烂(栈溢出)或者达成条件停止。

按"调用的位置"分(性能优化向)

这是你提到的尾递归所在的分类,也是性能优化的关键。

A. 头递归 (Head Recursion)

  • 特点 :先递归调用,拿到结果后,进行计算(或者说,递归调用在函数体的前面)。
  • 长相
clike 复制代码
int head(int n) {
    if (n == 0) return 0;
    // 先递归下去,等回来之后,还要做 +n 的操作
    return head(n - 1) + n; 
}
  • 缺点:必须把每一层的现场(比如这里的 n)都保存在栈里,等着"归"的时候用。容易栈溢出。

B. 尾递归 (Tail Recursion) ------ 你提到的那位

  • 特点 :递归调用是函数的最后一步操作。调用之后,函数不需要再做任何计算了,直接返回结果就行。
  • 长相
clike 复制代码
int tail(int n, int acc) {
    if (n == 0) return acc;
    // 计算已经在参数里做完了(acc + n),这里只是单纯的跳转
    return tail(n - 1, acc + n); 
}
  • 优点 :编译器可以进行尾调用优化 (TCO)。它不需要保留上一层的栈帧,直接把当前栈覆盖掉就行。这样,无论递归多少层,栈空间永远是 O(1) 的,不会栈溢出。

总结

分类维度 类型 关键特征
调用路数 线性递归 一层只调一次自己
树形递归 一层调多次自己
调用关系 直接递归 自己调自己
间接递归 你调我,我调你
调用位置 头递归 调完还要算
尾递归 调完直接返
相关推荐
nianniannnn7 小时前
力扣206.反转链表 92.反转链表II
算法·leetcode·链表
澈2078 小时前
哈希表实战:从原理到手写实现
算法·哈希算法
旖-旎8 小时前
哈希表(存在重复元素||)(4)
数据结构·c++·算法·leetcode·哈希算法·散列表
Run_Teenage8 小时前
Linux:认识信号,理解信号的产生和处理
linux·运维·算法
無限進步D8 小时前
蓝桥杯赛前刷题
c++·算法·蓝桥杯·竞赛
CoderCodingNo8 小时前
【GESP】C++二级真题 luogu-B4497, [GESP202603 二级] 数数
开发语言·c++·算法
磊 子8 小时前
八大排序之冒泡排序+选择排序
数据结构·算法·排序算法
We་ct8 小时前
LeetCode 50. Pow(x, n):从暴力法到快速幂的优化之路
开发语言·前端·javascript·算法·leetcode·typescript·
潇洒畅想8 小时前
1.1 从∑到∫:用循环理解求和与累积
java·数据结构·python·算法
郝学胜-神的一滴9 小时前
[简化版 GAMES 101] 计算机图形学 04:二维变换上
c++·算法·unity·godot·图形渲染·unreal engine·cesium