在 C 语言里,函数递归是一种函数调用自身的编程技术。下面开始逐一介绍。
一、什么是递归?
递归其实是⼀种解决问题的⽅法,在C语⾔中,递归就是函数⾃⼰调⽤⾃⼰。
int main()
{
printf("hehe\n");
main();//main函数中⼜调⽤了main函数
return 0;
}

5!= 5 * 4 * 3 * 2 * 1
4!= 4 * 3 * 2 * 1
所以:5!= 5 * 4!

{
if (n == 0)
return 1;
else
return n * Fact(n - 1);
}
int Fact(int n)
{
if (n == 0)
return 1;
else
return n * Fact(n - 1);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fact(n);
printf("%d\n", ret);
return 0;
}


Print(n)
如果n是1234,那表⽰为
Print(1234) //打印1234的每⼀位
其中1234中的4可以通过 % 10得到,那么
Print(1234)就可以拆分为两步:
1. Print(1234 / 10) //打印123的每⼀位
2. printf(1234 % 10) //打印4
完成上述2步,那就完成了1234每⼀位的打印
那么Print(123)⼜可以拆分为Print(123 / 10) + printf(123 % 10)
以此类推下去,就有
Print(1234)
==> Print(123) + printf(4)
==> Print(12) + printf(3)
==> Print(1) + printf(2)
==> printf(1)
直到被打印的数字变成⼀位数的时候,就不需要再拆分,递归结束。
那么代码完成也就⽐较清楚:
void Print(int n)
{
if (n > 9)
{
Print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
int m = 0;
scanf("%d", &m);
Print(m);
return 0;
}
输入和输出的结果:
在这里,我们运用到了大事化小的思路。
三、递归与迭代

{
if (n == 0)
return 1;
else
return n * Fact(n - 1);
}


factorial(5) 调用 5 * factorial(4)。
factorial(4) 调用 4 * factorial(3)。
factorial(3) 调用 3 * factorial(2)。
factorial(2) 调用 2 * factorial(1)。
factorial(1) 满足基本情况,返回 1。
然后逐步回溯计算:
factorial(2) 返回 2 * 1 = 2。
factorial(3) 返回 3 * 2 = 6。
factorial(4) 返回 4 * 6 = 24。
factorial(5) 返回 5 * 24 = 120。
优点:
代码简洁:递归可以让代码更加简洁、易读,尤其是处理一些具有递归结构的问题,如树的遍历、分治算法等。
易于理解:对于某些问题,递归的思路更贴合人类的思维方式,更容易设计和实现。
缺点:
性能问题:递归调用会频繁地进行函数调用和返回操作,带来额外的开销,可能会导致性能下降。
栈溢出风险:如果递归深度过大,会导致栈空间耗尽,引发栈溢出错误。
注意事项
要确保递归函数包含基本情况,防止无限递归。
注意递归深度,避免栈溢出。在必要时,可以考虑使用迭代(循环)来替代递归。
迭代:通常情况下,迭代的执行效率相对较高,因为它避免了函数调用栈的频繁操作,只是在循环结构内进行简单的指令重复执行,减少了额外的开销。
递归:递归由于不断地进行函数调用和返回,会有一定的时间和空间开销,尤其是在递归深度较大时,可能会出现栈溢出等性能问题。
代码可读性:
迭代:对于一些简单逻辑,迭代代码的结构清晰,易于理解和调试,直接通过循环条件和循环体就能明白代码的执行流程。
递归:递归代码在处理具有递归结构的问题(如树的遍历、分治算法等)时,代码可能更简洁,更符合人们对问题的分解式思考方式,但对于初学者或者复杂逻辑,理解起来可能有一定难度。
迭代和递归各有优缺点,在实际编程中,需要根据问题的特点、性能要求和代码的可读性来选择合适的方法。有时候,迭代和递归可以相互转换,通过合理的设计和优化,可以提高代码的性能和可维护性。