C语言需要掌握的基础知识点之递归

C语言需要掌握的基础知识点之递归

递归是C语言中一种重要的编程技术,它允许函数调用自身来解决问题。递归可以将复杂问题分解为更小的相似问题,直到达到基本情况。

递归的基本概念

递归是一个函数直接或间接调用自身的过程。每个递归函数必须包含两个部分:

基本情况:递归终止的条件

递归情况:函数调用自身的部分

递归的基本结构

复制代码
返回值类型 函数名(参数) {
    // 1. 基本情况(终止条件)
    if (满足终止条件) {
        return 基础解;
    }
    
    // 2. 递归情况
    return 函数名(修改后的参数);
}

经典的递归示例

阶乘计算

复制代码
#include <stdio.h>

// 递归计算阶乘
long factorial(int n) {
    // 基本情况
    if (n == 0 || n == 1) {
        return 1;
    }
    // 递归情况
    return n * factorial(n - 1);
}

int main() {
    int numbers[] = {0, 1, 5, 10};
    int count = sizeof(numbers) / sizeof(numbers[0]);
    
    for (int i = 0; i < count; i++) {
        printf("%d! = %ld\n", numbers[i], factorial(numbers[i]));
    }
    
    return 0;
}

斐波那契数列

复制代码
#include <stdio.h>

// 递归计算斐波那契数列
long fibonacci(int n) {
    // 基本情况
    if (n == 0) return 0;
    if (n == 1) return 1;
    
    // 递归情况
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// 优化版本:使用记忆化递归
long fibonacciMemo(int n, long memo[]) {
    if (n == 0) return 0;
    if (n == 1) return 1;
    
    // 如果已经计算过,直接返回结果
    if (memo[n] != -1) {
        return memo[n];
    }
    
    // 计算并存储结果
    memo[n] = fibonacciMemo(n - 1, memo) + fibonacciMemo(n - 2, memo);
    return memo[n];
}

int main() {
    int n = 10;
    
    printf("斐波那契数列前%d项:\n", n);
    for (int i = 0; i < n; i++) {
        printf("F(%d) = %ld\n", i, fibonacci(i));
    }
    
    // 使用记忆化递归
    printf("\n使用记忆化递归:\n");
    long memo[100];
    for (int i = 0; i < 100; i++) memo[i] = -1;
    
    for (int i = 0; i < n; i++) {
        printf("F(%d) = %ld\n", i, fibonacciMemo(i, memo));
    }
    
    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;
    }
    
    // 递归步骤:
    // 1. 将n-1个盘子从源柱移动到辅助柱
    hanoi(n - 1, from, aux, to);
    
    // 2. 将第n个盘子从源柱移动到目标柱
    printf("将盘子 %d 从 %c 移动到 %c\n", n, from, to);
    
    // 3. 将n-1个盘子从辅助柱移动到目标柱
    hanoi(n - 1, aux, to, from);
}

int main() {
    int n = 3;
    printf("汉诺塔问题,%d个盘子的移动步骤:\n", n);
    hanoi(n, 'A', 'C', 'B');
    return 0;
}

递归在数据结构中的应用

链表递归操作

复制代码
#include <stdio.h>
#include <stdlib.h>

// 链表节点定义
struct Node {
    int data;
    struct Node* next;
};

// 递归遍历链表
void recursiveTraverse(struct Node* node) {
    // 基本情况:空节点
    if (node == NULL) {
        return;
    }
    
    // 先处理当前节点
    printf("%d ", node->data);
    
    // 递归处理下一个节点
    recursiveTraverse(node->next);
}

// 递归反转链表
struct Node* recursiveReverse(struct Node* node) {
    // 基本情况:空节点或只有一个节点
    if (node == NULL || node->next == NULL) {
        return node;
    }
    
    // 递归反转剩余部分
    struct Node* newHead = recursiveReverse(node->next);
    
    // 将当前节点连接到反转后链表的末尾
    node->next->next = node;
    node->next = NULL;
    
    return newHead;
}

// 递归计算链表长度
int recursiveLength(struct Node* node) {
    if (node == NULL) {
        return 0;
    }
    return 1 + recursiveLength(node->next);
}

// 创建链表节点
struct Node* createNode(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

int main() {
    // 创建链表: 1 -> 2 -> 3 -> 4 -> 5
    struct Node* head = createNode(1);
    head->next = createNode(2);
    head->next->next = createNode(3);
    head->next->next->next = createNode(4);
    head->next->next->next->next = createNode(5);
    
    printf("原链表: ");
    recursiveTraverse(head);
    printf("\n");
    
    printf("链表长度: %d\n", recursiveLength(head));
    
    head = recursiveReverse(head);
    printf("反转后链表: ");
    recursiveTraverse(head);
    printf("\n");
    
    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* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

// 递归前序遍历
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 treeHeight(struct TreeNode* root) {
    if (root == NULL) {
        return 0;
    }
    
    int leftHeight = treeHeight(root->left);
    int rightHeight = treeHeight(root->right);
    
    return 1 + (leftHeight > rightHeight ? leftHeight : rightHeight);
}

// 递归查找节点
struct TreeNode* searchNode(struct TreeNode* root, int key) {
    if (root == NULL || root->data == key) {
        return root;
    }
    
    struct TreeNode* leftResult = searchNode(root->left, key);
    if (leftResult != NULL) {
        return leftResult;
    }
    
    return searchNode(root->right, key);
}

int main() {
    // 创建二叉树
    //       1
    //      / \
    //     2   3
    //    / \
    //   4   5
    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");
    
    printf("树的高度: %d\n", treeHeight(root));
    
    int searchKey = 4;
    struct TreeNode* found = searchNode(root, searchKey);
    if (found != NULL) {
        printf("找到节点 %d\n", searchKey);
    } else {
        printf("未找到节点 %d\n", searchKey);
    }
    
    return 0;
}

递归的数学应用

最大公约数(GCD)

复制代码
#include <stdio.h>

// 递归计算最大公约数(欧几里得算法)
int gcd(int a, int b) {
    // 基本情况
    if (b == 0) {
        return a;
    }
    // 递归情况
    return gcd(b, a % b);
}

int main() {
    int pairs[][2] = {{48, 18}, {56, 42}, {101, 103}};
    int count = sizeof(pairs) / sizeof(pairs[0]);
    
    for (int i = 0; i < count; i++) {
        int a = pairs[i][0];
        int b = pairs[i][1];
        printf("gcd(%d, %d) = %d\n", a, b, gcd(a, b));
    }
    
    return 0;
}

幂运算

复制代码
#include <stdio.h>

// 递归计算幂
double power(double base, int exponent) {
    // 基本情况
    if (exponent == 0) {
        return 1;
    }
    if (exponent == 1) {
        return base;
    }
    
    // 处理负指数
    if (exponent < 0) {
        return 1 / power(base, -exponent);
    }
    
    // 递归情况:分治策略
    if (exponent % 2 == 0) {
        double half = power(base, exponent / 2);
        return half * half;
    } else {
        return base * power(base, exponent - 1);
    }
}

int main() {
    printf("2^10 = %.0f\n", power(2, 10));
    printf("3^4 = %.0f\n", power(3, 4));
    printf("5^-2 = %.4f\n", power(5, -2));
    printf("2.5^3 = %.4f\n", power(2.5, 3));
    
    return 0;
}

递归的字符串操作

字符串反转

复制代码
#include <stdio.h>
#include <string.h>

// 递归反转字符串
void reverseString(char str[], int start, int end) {
    // 基本情况
    if (start >= end) {
        return;
    }
    
    // 交换首尾字符
    char temp = str[start];
    str[start] = str[end];
    str[end] = temp;
    
    // 递归处理子字符串
    reverseString(str, start + 1, end - 1);
}

// 递归判断回文串
int isPalindrome(char str[], int start, int end) {
    // 基本情况
    if (start >= end) {
        return 1;
    }
    
    // 如果首尾字符不相等,不是回文
    if (str[start] != str[end]) {
        return 0;
    }
    
    // 递归检查子字符串
    return isPalindrome(str, start + 1, end - 1);
}

int main() {
    char str1[] = "hello";
    char str2[] = "racecar";
    
    printf("原字符串: %s\n", str1);
    reverseString(str1, 0, strlen(str1) - 1);
    printf("反转后: %s\n", str1);
    
    printf("\n字符串 '%s' 是回文吗? %s\n", 
           str2, isPalindrome(str2, 0, strlen(str2) - 1) ? "是" : "否");
    
    return 0;
}

递归的注意事项和优化

尾递归优化

复制代码
#include <stdio.h>

// 普通递归阶乘
long factorial(int n) {
    if (n == 0 || n == 1) {
        return 1;
    }
    return n * factorial(n - 1);  // 不是尾递归
}

// 尾递归阶乘
long factorialTail(int n, long accumulator) {
    if (n == 0 || n == 1) {
        return accumulator;
    }
    return factorialTail(n - 1, n * accumulator);  // 尾递归
}

// 包装函数
long factorialOptimized(int n) {
    return factorialTail(n, 1);
}

int main() {
    int n = 5;
    printf("%d! = %ld (普通递归)\n", n, factorial(n));
    printf("%d! = %ld (尾递归)\n", n, factorialOptimized(n));
    
    return 0;
}

递归深度和栈溢出

复制代码
#include <stdio.h>

// 演示栈溢出的递归
void infiniteRecursion(int n) {
    printf("递归深度: %d\n", n);
    infiniteRecursion(n + 1);  // 无限递归,会导致栈溢出
}

// 安全的递归,有终止条件
void safeRecursion(int n, int maxDepth) {
    if (n > maxDepth) {
        printf("达到最大深度 %d\n", maxDepth);
        return;
    }
    printf("当前深度: %d\n", n);
    safeRecursion(n + 1, maxDepth);
}

int main() {
    // 不要调用 infiniteRecursion(1),会导致栈溢出
    printf("安全递归演示:\n");
    safeRecursion(1, 10);
    
    return 0;
}

递归与迭代的比较

复制代码
#include <stdio.h>
#include <time.h>

// 递归斐波那契
long fibRecursive(int n) {
    if (n <= 1) return n;
    return fibRecursive(n - 1) + fibRecursive(n - 2);
}

// 迭代斐波那契
long fibIterative(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() {
    int n = 40;
    clock_t start, end;
    
    printf("计算斐波那契数列第%d项:\n", n);
    
    // 测试迭代版本
    start = clock();
    long result1 = fibIterative(n);
    end = clock();
    printf("迭代结果: %ld, 时间: %f秒\n", result1, (double)(end - start) / CLOCKS_PER_SEC);
    
    // 测试递归版本
    start = clock();
    long result2 = fibRecursive(n);
    end = clock();
    printf("递归结果: %ld, 时间: %f秒\n", result2, (double)(end - start) / CLOCKS_PER_SEC);
    
    return 0;
}
相关推荐
黑金IT5 小时前
PHP 后台通过权限精制飞书多维表格
开发语言·php·飞书
脚踏实地的大梦想家6 小时前
【Go】P11 掌握 Go 语言函数(二):进阶玩转高阶函数、闭包与 Defer/Panic/Recover
开发语言·后端·golang
秋空樱雨6 小时前
C++入门
开发语言·c++
咬_咬6 小时前
C++仿mudo库高并发服务器项目:Buffer模块
服务器·开发语言·c++·缓冲区·buffer·muduo库
江公望7 小时前
Qt qmlplugindump浅谈
开发语言·qt·qml
曦樂~7 小时前
【Qt】文件操作/事件--mainwindow做编辑器
开发语言·qt
敲代码的瓦龙7 小时前
西邮移动应用开发实验室2025年二面题解
开发语言·c++·算法
laocooon5238578867 小时前
一个适合新手的训练C题
c语言·开发语言
C嘎嘎嵌入式开发7 小时前
(21)100天python从入门到拿捏《XML 数据解析》
xml·开发语言·python