递归函数是函数直接或间接调用自身的编程技术。东巴文(db-w.cn) 将带你深入理解递归函数,掌握递归编程的核心技能。
💡 东巴文观点:递归是将复杂问题分解为简单问题的艺术,通过函数自我调用实现问题的自我相似性解决。
东巴文说明:递归是函数直接或间接调用自身的过程。
东巴文递归结构:
递归函数
├── 基准情况(Base Case)
│ └── 终止递归的条件
├── 递归情况(Recursive Case)
│ └── 函数调用自身
└── 递归调用(Recursive Call)
└── 向基准情况靠近
返回类型 函数名(参数) {
if (基准情况) {
// 返回结果,不再递归
return 结果;
} else {
// 递归调用
return 函数名(更小的参数);
}
}
#include <stdio.h>
// 递归函数:倒数
void countdown(int n) {
// 基准情况
if (n <= 0) {
printf("发射!\n");
return;
}
// 递归情况
printf("%d\n", n);
countdown(n - 1); // 递归调用
}
int main() {
printf("=== 东巴文第一个递归函数 ===\n\n");
countdown(5);
return 0;
}
东巴文执行过程:
countdown(5)
打印 5
countdown(4)
打印 4
countdown(3)
打印 3
countdown(2)
打印 2
countdown(1)
打印 1
countdown(0)
打印 "发射!"
返回
返回
返回
返回
返回
返回
#include <stdio.h>
// 递归计算阶乘
long factorial(int n) {
// 基准情况
if (n <= 1) {
return 1;
}
// 递归情况
return n * factorial(n - 1);
}
// 迭代计算阶乘
long factorial_iterative(int n) {
long result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
int main() {
printf("=== 东巴文阶乘递归 ===\n\n");
printf("递归方法:\n");
printf("5! = %ld\n", factorial(5));
printf("10! = %ld\n", factorial(10));
printf("\n迭代方法:\n");
printf("5! = %ld\n", factorial_iterative(5));
printf("10! = %ld\n", factorial_iterative(10));
return 0;
}
东巴文阶乘递归过程:
factorial(5)
= 5 * factorial(4)
= 5 * 4 * factorial(3)
= 5 * 4 * 3 * factorial(2)
= 5 * 4 * 3 * 2 * factorial(1)
= 5 * 4 * 3 * 2 * 1
= 120
#include <stdio.h>
// 递归计算斐波那契数列
long fibonacci(int n) {
// 基准情况
if (n <= 1) {
return n;
}
// 递归情况
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 迭代计算斐波那契数列
long fibonacci_iterative(int n) {
if (n <= 1) return n;
long a = 0, b = 1, c;
for (int i = 2; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return b;
}
int main() {
printf("=== 东巴文斐波那契递归 ===\n\n");
printf("递归方法:\n");
printf("斐波那契数列前10项:\n");
for (int i = 0; i < 10; i++) {
printf("%ld ", fibonacci(i));
}
printf("\n");
printf("\n迭代方法:\n");
printf("斐波那契数列前10项:\n");
for (int i = 0; i < 10; i++) {
printf("%ld ", fibonacci_iterative(i));
}
printf("\n");
return 0;
}
#include <stdio.h>
// 汉诺塔递归解法
void hanoi(int n, char from, char to, char aux) {
// 基准情况
if (n == 1) {
printf("移动盘子1从%c到%c\n", from, to);
return;
}
// 递归情况
hanoi(n - 1, from, aux, to); // 将n-1个盘子从from移到aux
printf("移动盘子%d从%c到%c\n", n, from, to); // 移动第n个盘子
hanoi(n - 1, aux, to, from); // 将n-1个盘子从aux移到to
}
int main() {
printf("=== 东巴文汉诺塔递归 ===\n\n");
printf("3个盘子的汉诺塔:\n");
hanoi(3, 'A', 'C', 'B');
return 0;
}
#include <stdio.h>
// 递归二分查找
int binarySearch(int arr[], int left, int right, int target) {
// 基准情况:未找到
if (left > right) {
return -1;
}
int mid = left + (right - left) / 2;
// 基准情况:找到
if (arr[mid] == target) {
return mid;
}
// 递归情况
if (arr[mid] < target) {
return binarySearch(arr, mid + 1, right, target); // 搜索右半部分
} else {
return binarySearch(arr, left, mid - 1, target); // 搜索左半部分
}
}
int main() {
printf("=== 东巴文二分查找递归 ===\n\n");
int arr[] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
int size = sizeof(arr) / sizeof(arr[0]);
int target = 7;
int index = binarySearch(arr, 0, size - 1, target);
if (index != -1) {
printf("找到%d,位置:%d\n", target, index);
} else {
printf("未找到%d\n", target);
}
return 0;
}
#include <stdio.h>
// 递归计算最大公约数(欧几里得算法)
int gcd(int a, int b) {
// 基准情况
if (b == 0) {
return a;
}
// 递归情况
return gcd(b, a % b);
}
// 迭代计算最大公约数
int gcd_iterative(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
int main() {
printf("=== 东巴文最大公约数递归 ===\n\n");
printf("递归方法:\n");
printf("gcd(48, 18) = %d\n", gcd(48, 18));
printf("gcd(56, 42) = %d\n", gcd(56, 42));
printf("\n迭代方法:\n");
printf("gcd(48, 18) = %d\n", gcd_iterative(48, 18));
printf("gcd(56, 42) = %d\n", gcd_iterative(56, 42));
return 0;
}
东巴文递归优点表:
| 优点 | 说明 | 东巴文解释 |
|---|---|---|
| 代码简洁 | 递归代码通常更简洁 | 易于理解 |
| 问题分解 | 将复杂问题分解为简单问题 | 分而治之 |
| 自然表达 | 某些问题天然适合递归 | 如树遍历 |
| 减少代码量 | 避免重复代码 | 提高效率 |
东巴文递归缺点表:
| 缺点 | 说明 | 东巴文解释 |
|---|---|---|
| 效率较低 | 递归调用有额外开销 | 占用栈空间 |
| 栈溢出 | 深度递归可能导致栈溢出 | 需要限制深度 |
| 难以调试 | 递归调用链复杂 | 不易追踪 |
| 重复计算 | 可能重复计算相同子问题 | 需要优化 |
#include <stdio.h>
#include <time.h>
// 递归计算斐波那契
long fib_recursive(int n) {
if (n <= 1) return n;
return fib_recursive(n - 1) + fib_recursive(n - 2);
}
// 迭代计算斐波那契
long fib_iterative(int n) {
if (n <= 1) return n;
long a = 0, b = 1, c;
for (int i = 2; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return b;
}
int main() {
printf("=== 东巴文递归 vs 迭代性能对比 ===\n\n");
int n = 35;
clock_t start, end;
// 递归方法
start = clock();
long result1 = fib_recursive(n);
end = clock();
printf("递归方法:fib(%d) = %ld\n", n, result1);
printf("耗时:%.3f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
// 迭代方法
start = clock();
long result2 = fib_iterative(n);
end = clock();
printf("\n迭代方法:fib(%d) = %ld\n", n, result2);
printf("耗时:%.3f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
return 0;
}
东巴文对比表:
| 特性 | 递归 | 迭代 | 东巴文说明 |
|---|---|---|---|
| 代码简洁性 | 简洁 | 复杂 | 递归更简洁 |
| 执行效率 | 较低 | 较高 | 迭代更高效 |
| 内存占用 | 较大 | 较小 | 迭代更节省 |
| 栈溢出风险 | 有 | 无 | 迭代更安全 |
| 适用场景 | 问题自相似 | 线性处理 | 根据问题选择 |
东巴文说明:尾递归是递归调用在函数的最后一步,编译器可以优化为迭代。
#include <stdio.h>
// 普通递归
long factorial_normal(int n) {
if (n <= 1) return 1;
return n * factorial_normal(n - 1); // 不是尾递归
}
// 尾递归
long factorial_tail(int n, long accumulator) {
if (n <= 1) return accumulator;
return factorial_tail(n - 1, n * accumulator); // 尾递归
}
// 包装函数
long factorial(int n) {
return factorial_tail(n, 1);
}
int main() {
printf("=== 东巴文尾递归优化 ===\n\n");
printf("普通递归:5! = %ld\n", factorial_normal(5));
printf("尾递归:5! = %ld\n", factorial(5));
return 0;
}
东巴文说明:记忆化递归使用缓存存储已计算的结果,避免重复计算。
#include <stdio.h>
#define MAX_N 100
// 记忆化缓存
long cache[MAX_N] = {0};
// 记忆化递归斐波那契
long fib_memoization(int n) {
// 基准情况
if (n <= 1) return n;
// 检查缓存
if (cache[n] != 0) {
return cache[n];
}
// 计算并缓存
cache[n] = fib_memoization(n - 1) + fib_memoization(n - 2);
return cache[n];
}
int main() {
printf("=== 东巴文记忆化递归 ===\n\n");
printf("斐波那契数列前20项:\n");
for (int i = 0; i < 20; i++) {
printf("%ld ", fib_memoization(i));
}
printf("\n");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define MAX_DEPTH 1000
// 限制递归深度
int recursiveFunction(int n, int depth) {
// 检查递归深度
if (depth > MAX_DEPTH) {
printf("错误:递归深度超过限制\n");
return -1;
}
// 基准情况
if (n <= 0) {
return 0;
}
// 递归情况
return n + recursiveFunction(n - 1, depth + 1);
}
int main() {
printf("=== 东巴文限制递归深度 ===\n\n");
int result = recursiveFunction(100, 0);
printf("结果:%d\n", result);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
// 树节点
struct TreeNode {
int data;
struct TreeNode *left;
struct TreeNode *right;
};
// 创建树节点
struct TreeNode* createNode(int data) {
struct TreeNode *node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
// 前序遍历(递归)
void preorderTraversal(struct TreeNode *root) {
if (root == NULL) return;
printf("%d ", root->data); // 访问根节点
preorderTraversal(root->left); // 遍历左子树
preorderTraversal(root->right); // 遍历右子树
}
// 中序遍历(递归)
void inorderTraversal(struct TreeNode *root) {
if (root == NULL) return;
inorderTraversal(root->left); // 遍历左子树
printf("%d ", root->data); // 访问根节点
inorderTraversal(root->right); // 遍历右子树
}
// 后序遍历(递归)
void postorderTraversal(struct TreeNode *root) {
if (root == NULL) return;
postorderTraversal(root->left); // 遍历左子树
postorderTraversal(root->right); // 遍历右子树
printf("%d ", root->data); // 访问根节点
}
int main() {
printf("=== 东巴文树的递归遍历 ===\n\n");
// 构建树
struct TreeNode *root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
printf("前序遍历:");
preorderTraversal(root);
printf("\n");
printf("中序遍历:");
inorderTraversal(root);
printf("\n");
printf("后序遍历:");
postorderTraversal(root);
printf("\n");
return 0;
}
#include <stdio.h>
// 分区函数
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
// 交换arr[i]和arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// 交换arr[i+1]和arr[high]
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return i + 1;
}
// 快速排序(递归)
void quickSort(int arr[], int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1); // 排序左半部分
quickSort(arr, pi + 1, high); // 排序右半部分
}
}
int main() {
printf("=== 东巴文快速排序递归 ===\n\n");
int arr[] = {10, 7, 8, 9, 1, 5};
int size = sizeof(arr) / sizeof(arr[0]);
printf("原数组:");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
quickSort(arr, 0, size - 1);
printf("排序后:");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
// ✅ 正确:有基准情况
int factorial(int n) {
if (n <= 1) return 1; // 基准情况
return n * factorial(n - 1);
}
// ❌ 错误:没有基准情况
int factorial_bad(int n) {
return n * factorial_bad(n - 1); // 无限递归
}
// ✅ 正确:向基准情况靠近
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1); // n-1向基准情况靠近
}
// ❌ 错误:不向基准情况靠近
int factorial_bad(int n) {
if (n <= 1) return 1;
return n * factorial_bad(n); // n不变,不会到达基准情况
}
// ❌ 错误:重复计算
int fib(int n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2); // 大量重复计算
}
// ✅ 正确:使用记忆化
int cache[100] = {0};
int fib_memo(int n) {
if (n <= 1) return n;
if (cache[n] != 0) return cache[n];
cache[n] = fib_memo(n - 1) + fib_memo(n - 2);
return cache[n];
}
// 递归:代码简洁但效率低
int factorial_recursive(int n) {
if (n <= 1) return 1;
return n * factorial_recursive(n - 1);
}
// 迭代:效率更高
int factorial_iterative(int n) {
int result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
完成本章学习后,请确认:
掌握递归函数后,你可以继续学习:
如果遇到问题,欢迎访问 东巴文(db-w.cn) 获取帮助!
东巴文(db-w.cn) - 让编程学习更简单
📦 东巴文递归函数提示:递归是解决问题的优雅方式,掌握递归是成为优秀程序员的关键。在 db-w.cn,我们会通过大量实例帮你掌握递归函数的使用!