递归函数是一种可以调用自身的函数。
例:使用递归求一个数(num)的阶乘:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num;
scanf("%d",&num); /* 从控制台接收一个数 */
int a = fact(num); /* 定义一个整形变量用于存储fact()函数返回的结果 */
printf("%d!=%d\n",num,a);
system("pause");
return 0;
}
//定义一个函数fact()用递归求一个数的阶乘
int fact(int n)
{
if (n < 0)
return 0; //当 < 0 时返回 0 表示一个错误
else if (n == 0)
return 1; /* 0! = 1 */
else if (n == 1)
return 1; /* 1! = 1 */
else
return n * fact ( n - 1 ) ; /* 调用自身 */
}
递归过程中的两个基本阶段:
1)递推
-->在递推阶段,每一个递归调用通过进一步调用自己来记住这次递归的全过程。挡其中有满足终止条件时,递归结束。
如:在计算num的阶乘时,终止条件时当n=1和0,此时函数只需简单的返回1即可。
-->每一个递归函数都必须拥有至少一个终止条件,否则,递推阶段就永远不会结束了
2)回归
-->递推阶段结束后,处理过程进入回归阶段,在这之前的函数调用以逆序的方式回归,直到最初调用的函数返回为止。
在C语言中,基本上可以说一个可执行程序由四个区域组成:代码段、静态数据区、堆与栈。
代码段包含程序运行时所执行的机器指令。
静态数据区包含在程序生命周期内一直持久的数据(如全局变量和静态变量)。
堆包含程序运行时动态分配的存储空间(比如malloc()函数分配的内存)。
栈包含函数的调用信息。
当C程序中调用了一个函数时,栈会分配一块空间来保存与这个调用相关的信息。每一个调用都是活跃的,栈上的那块存储空间称为活跃记录(栈帧),活跃记录(栈帧)由5个区域组成:输入参数、返回值空间、计算表达式时用到的临时存储空间、函数调用时保存的状态信息以及输出参数。
输入参数是传递到活跃记录(栈帧)中的参数。
输出参数是传递给任何在活跃记录(栈帧)中调用的函数所使用的。
一个输出参数就称为栈中下一个活跃记录的输入参数。
函数调用产生的活跃记录将一直存于栈中直到这个函数调用结束。
至此,分析例题(假设我们计算 4的阶乘):
1)递推阶段:初始调用fact()函数会在栈中产生一个活跃记录,输入参数 n = 4。由于这个调用没有满足函数的终止条件,因此,fact()继续以 n = 3(fact( n - 1)) 位参数递归调用,这将在栈上创建另一个活跃记录,但此时的输入参数 3 为第一个活跃期的输出参数。因为正是第一个活跃期内调用fact()产生了第二个活跃期。这个过程一直持续直到 n = 1,此时满足终止条件,fact()将返回 1。
2)回归阶段:当 n = 1时的活跃期结束,返回值为1;结果就是 n = 2时递归计算结果为 2 * 1 = 2,因此n = 2时的活跃期也将结束,返回值为2;然后是 n = 3时递归计算结果就是3 * 2 = 6,因此n = 3时的活跃期也将结束,返回值为6;最终当 n = 4时递归计算结果将表示为4 * 6 = 24,n = 4时的活跃期将结束,返回值为24;
3)此时,函数已经从最初的调用中返回,递归过程结束。
例:使用递归求一个数(num)的阶乘:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num;
scanf("%d",&num); /* 从控制台接收一个数 */
int a = fact(num); /* 定义一个整形变量用于存储fact()函数返回的结果 */
printf("%d!=%d\n",num,a);
system("pause");
return 0;
}
//定义一个函数fact()用递归求一个数的阶乘
int fact(int n)
{
if (n < 0)
return 0; //当 < 0 时返回 0 表示一个错误
else if (n == 0)
return 1; /* 0! = 1 */
else if (n == 1)
return 1; /* 1! = 1 */
else
return n * fact ( n - 1 ) ; /* 调用自身 */
}
递归过程中的两个基本阶段:
1)递推
-->在递推阶段,每一个递归调用通过进一步调用自己来记住这次递归的全过程。挡其中有满足终止条件时,递归结束。
如:在计算num的阶乘时,终止条件时当n=1和0,此时函数只需简单的返回1即可。
-->每一个递归函数都必须拥有至少一个终止条件,否则,递推阶段就永远不会结束了
2)回归
-->递推阶段结束后,处理过程进入回归阶段,在这之前的函数调用以逆序的方式回归,直到最初调用的函数返回为止。
在C语言中,基本上可以说一个可执行程序由四个区域组成:代码段、静态数据区、堆与栈。
代码段包含程序运行时所执行的机器指令。
静态数据区包含在程序生命周期内一直持久的数据(如全局变量和静态变量)。
堆包含程序运行时动态分配的存储空间(比如malloc()函数分配的内存)。
栈包含函数的调用信息。
当C程序中调用了一个函数时,栈会分配一块空间来保存与这个调用相关的信息。每一个调用都是活跃的,栈上的那块存储空间称为活跃记录(栈帧),活跃记录(栈帧)由5个区域组成:输入参数、返回值空间、计算表达式时用到的临时存储空间、函数调用时保存的状态信息以及输出参数。
输入参数是传递到活跃记录(栈帧)中的参数。
输出参数是传递给任何在活跃记录(栈帧)中调用的函数所使用的。
一个输出参数就称为栈中下一个活跃记录的输入参数。
函数调用产生的活跃记录将一直存于栈中直到这个函数调用结束。
至此,分析例题(假设我们计算 4的阶乘):
1)递推阶段:初始调用fact()函数会在栈中产生一个活跃记录,输入参数 n = 4。由于这个调用没有满足函数的终止条件,因此,fact()继续以 n = 3(fact( n - 1)) 位参数递归调用,这将在栈上创建另一个活跃记录,但此时的输入参数 3 为第一个活跃期的输出参数。因为正是第一个活跃期内调用fact()产生了第二个活跃期。这个过程一直持续直到 n = 1,此时满足终止条件,fact()将返回 1。
2)回归阶段:当 n = 1时的活跃期结束,返回值为1;结果就是 n = 2时递归计算结果为 2 * 1 = 2,因此n = 2时的活跃期也将结束,返回值为2;然后是 n = 3时递归计算结果就是3 * 2 = 6,因此n = 3时的活跃期也将结束,返回值为6;最终当 n = 4时递归计算结果将表示为4 * 6 = 24,n = 4时的活跃期将结束,返回值为24;
3)此时,函数已经从最初的调用中返回,递归过程结束。