学科分类
目录
C语言

递归函数的概念

一种计算过程,如果其中每一步都要用到前一步或前几步的结果,这个计算就是可递归的。用递归过程定义的函数,称为递归函数。在数学运算中,经常会遇到计算多个连续自然数之间的和的情况,例如,要计算1~n之间自然数之和,就需要先计算1加2的结果,用这个结果加3再得到一个结果,用新得到的结果加4…,以此类推,直到用1~(n-1)之间所有数的和加n,就得到了1~n之间的自然数之和。

在程序开发中,要想完成上述功能,除了使用循环,还可以通过函数的递归调用实现,所谓递归调用就是函数内部调用本身的过程。定义计算1~n之间自然数之和的递归函数,示例代码如下:

int getsum(int n)
{
    int sum=0;
    sum = getsum(n - 1);        //调用函数本身
    return sum + n;                //返回sum+n结果,即getsum(n-1)+n结果
}

上述代码定义了getsum()函数,用于计算1~n自然数之和,在函数内部定义了变量sum,并在函数内部调用了函数本身,将求和结果赋值给sum。需要注意的是,getsum()函数的参数为n,在函数内部调用本身时,函数参数为n-1,它表明先计算1~(n-1)之间的自然数之和,最后将(sum+n)的结果返回,这就完成了1~n自然数求和。

定义好getsum()函数之后,在main()函数中调用,系统却抛出“栈溢出”异常,仔细分析程序发现,getsum()函数是一个无止境的函数调用,即没有调用结束条件。例如,传入参数4,计算getsum(4)时,函数会先计算getsum(3);计算getsum(3)时会先计算getsum(2)…,该过程如图1所示。

图1 getsum(4)无止境递归过程

由图1可知,getsum()函数会从4开始递减,一直递归调用下去,因为函数调用开销较大,很快就会占满栈内存,造成栈溢出导致程序崩溃。程序是求算1~n之间的自然数之和,应当在n递减至1时就停止函数递归调用。如果没有停止条件,递归就是一个内存开销较大的无限循环。由此可以得出,递归函数要满足两个条件:

(1) 函数调用本身,且每一次调用本身时,必须是(在某种意义上)更接近于解。

(2) 递归必须有结束条件。

通过上述分析,可以修改getsum()函数的定义,添加终止条件,具体如例1所示。

例1 getSum.c

 1    #include <stdio.h>
 2    int getsum(int n)
 3    {
 4        if (n == 1)                        //终止条件:n=1
 5            return 1;                    //n=1时,和为1
 6        int temp = getsum(n - 1);        //调用函数本身
 7        return temp + n;                //返回sum+n结果,即getsum(n-1)+n结果
 8    }
 9    int main()
 10    {
 11        int sum = getsum(4);            //调用递归函数,获得1~4的和
 12         printf("sum = %d\n",sum);        //打印结果
 13        return 0;
 14    }

例1运行结果如图1所示。

图2 例1运行结果

在例1中,第2~9行代码定义了getsum()函数;第11行代码调用getsum()函数计算1~4之间的自然数之和,并赋值给变量sum。第12行代码调用printf()函数输出sum的值。由图7-18可知,调用getsum()函数计算的1~4之间的自然数之和为10。

在本案例中,getsum()函数添加了递归结束条件:n=1,当n从4递减至1时,函数递归结束。下面结合例7-11代码分析getsum(4)的递归调用过程。

(1)n=4,getsum(4)=temp+4=getsum(3)+4。

(2)n=3,getsum(3)=temp+3=getsum(2)+3。

(3)n=2,getsum(2)=temp+2=getsum(1)+2。

(4)n=1,getsum(1)=1,即temp值为1。

递归到n=1时,getsum(1)值为1,将上述过程反推,如下所示。

(1)getsum(2)=getsum(1)+2=1+2=3。

(2)getsum(3)=getsum(2)+3=3+3=6。

(3)getsum(4)=getsum(3)+4=6+4=10。

最终得出1~4之间的自然数之和为10。由于函数的递归调用过程比较复杂,接下来通过一个图例来分析整个调用过程,如图3所示。

图3 getsum(4)递归调用

图3描述了递归调用的过程,整个递归过程中getsum()函数被调用了4次,每次调用时,n的值都会递减。当n的值为1时,所有递归调用的函数都会以相反的顺序相继结束,所有的返回值会进行累加,最终得到的结果为10。

点击此处
隐藏目录