:函数递归)
目录1. 什么是递归2. 递归的核心要素3. 递归经典案例3.1 求n的阶乘3.2 顺序打印一个整数的每一位4. 递归的问题与优化4.1 栈溢出风险5. 递归与循环的选择1. 什么是递归递归是一种编程技术指的是一个函数在其定义内部调用自身。最简单的递归程序虽然是错误的#includestdio.hintmain(){printf(hehe\n);main();// main函数自己调用自己return0;}这个程序会一直打印hehe直到程序崩溃。因为它是死递归没有终止条件最终会导致栈溢出。生活类比俄罗斯套娃打开一个大娃娃里面还有一个小娃娃再打开还有更小的……镜子中的镜子两面镜子对着照里面会出现无数层影像递归的核心思想就是把一个大型复杂问题层层转化为一个与原问题相似、但规模较小的子问题来求解直到子问题不能再拆分递归就结束了大事化小。2. 递归的核心要素一个正确的递归函数必须包含两个关键部分终止条件基础情况不再进行递归调用、能直接返回结果的特定条件。没有它递归会无限进行下去最终导致栈溢出。递归调用递推阶段函数自己调用自己每次调用时问题的规模都要比上一次更小逐步逼近终止条件。3. 递归经典案例3.1 求n的阶乘题目计算正整数 n 的阶乘0! 1不考虑溢出数学公式当 n 0 时0! 1当 n 0 时n! n × (n-1)!代码实现#includestdio.hintFact(intn){if(n0)return1;// 终止条件elsereturnn*Fact(n-1);// 递归调用规模变小}intmain(){intn0;scanf(%d,n);intretFact(n);printf(%d\n,ret);return0;}执行过程以 n5 为例Fact(5) 5 * Fact(4) 5 * 4 * Fact(3) 5 * 4 * 3 * Fact(2) 5 * 4 * 3 * 2 * Fact(1) 5 * 4 * 3 * 2 * 1 * Fact(0) 5 * 4 * 3 * 2 * 1 * 1 120递归写法 vs 循环写法递归写法intFact(intn){if(n0)return1;elsereturnn*Fact(n-1);}循环写法intFact(intn){intret1;for(inti1;in;i){ret*i;}returnret;}3.2 顺序打印一个整数的每一位题目输入一个正整数按顺序打印它的每一位数字。输入1234 → 输出1 2 3 4输入520 → 输出5 2 0思路分析一个数的最低位最容易得到1234 % 10 4去掉最低位1234 / 10 123把问题拆解为先打印前面所有位再打印最后一位当数字变成一位数时直接打印不再拆分代码实现#includestdio.hvoidPrint(intn){if(n9)// 如果不是一位数{Print(n/10);// 先递归打印前面所有位}printf(%d ,n%10);// 再打印最后一位}intmain(){intm0;scanf(%d,m);Print(m);return0;}执行过程以 1234 为例Print(1234) → Print(123) → Print(12) → Print(1) → printf(1) → printf(2) → printf(3) → printf(4) 输出结果1 2 3 44. 递归的问题与优化4.1 栈溢出风险每次函数调用都需要在内存的栈区申请一块空间称为栈帧来保存局部变量和函数调用信息。如果递归层次太深栈空间会被耗尽导致栈溢出。#includestdio.hintcount0;voidtest(){count;printf(当前递归深度%d\n,count);intbuffer[1000]{0};// 占用栈空间test();// 无限递归}intmain(){test();return0;}运行到一定深度后程序会崩溃因为栈空间被耗尽了。5. 递归与循环的选择很多递归问题都可以改写成循环版本循环通常效率更高。求阶乘对比递归写法intFact(intn){if(n0)return1;elsereturnn*Fact(n-1);}循环写法intFact(intn){intret1;for(inti1;in;i){ret*i;}returnret;}选择建议递归的优点是代码简洁、思路清晰适合树/图遍历、分治算法、回溯算法等场景循环的优点是效率高没有栈溢出风险一般建议递归深度 100 层且没有大量重复计算时可以放心使用递归如果递归存在明显性能问题改成循环版本总结递归就是函数自己调用自己记住两点终止条件和递归调用。终止条件让递归停下来递归调用让问题规模不断变小。递归能让代码变得很简洁但要注意栈溢出风险深度超过100层时建议改成循环。