C++ 初学者指南 第五篇(12)

来源:互联网 发布:金融方面的数据挖掘 编辑:程序博客网 时间:2024/05/20 09:11

必备技能5.12:递归
    本章中我们需要最后讨论的就是递归。递归有时也被称为循环定义。递归就是用自身来定义自己。在编程中,递归就是函数自己调用自己。自己调用自己的函数我们就称之为递归函数。
    典型的递归函数就是factr(), 它用来计算一个整数的阶乘。N的阶乘就是从1到N的所有数的乘积。例如,3的阶乘就是1×2×3,或者说是6。下面的程序用到了factr()函数的递归形式和循环形式。
/

/该程序演示了递归的用法#include <iostream>using namespace std;int factr(int n);int fact(int n);int main(){    //使用递归    cout << "4 factorial is " << factr(4);    cout << "\n";    //使用循环    cout << "4 factorial is " << fact(4);    cout << "\n";    return 0;}//递归int factr(int n){    int answer;    if ( n== 1) return (1);    answer = factr(n-1) * n; //递归调用函数factr()    return answer;}//循环int fact ( int n ){    int t, answer;    answer =1;    for ( t = 1; t <= n ; t++)    {        answer = answer * t;    }    return (answer);}

    采用循环方式计算阶乘的fact()函数比较简单。其中使用了一个从1开始的循环,每次都对乘积的结果再乘以当前的循环数。
    采用递归方式的函数factr()有点复杂。当函数factr()接收的参数为1的时候,函数就返回1;否则,就返回factr(n-1)与n的乘积。这种方式一直进行到n等于1的时候,函数调用才依次返回。例如,当计算2的阶乘的时候,第一次调用factr()的时候会导致再次调用该函数,传入参数1。此时函数返回1,然后这个1和2相乘得到阶乘为2。我们可以在函数factr()中增加cout语句,这样就可以看到每次factr()被调用的级别和其返回的值是多少。
    但函数调用自己的时候,局部变量和形参都会被重新分配存储空间(通常是分配在系统的栈空间上),函数会从头开始使用这些新的变量来进行计算。当每次函数返回的时候,函数用的局部变量和形参变量就会被从栈空间中移除,程序返回到调用处的下一条指令处继续执行。递归就像“望远镜”一样可以进行伸缩。必须明确,大部分的递归程序实际上并不能减少代码量。另外,递归函数的执行要比对等的循环方式的函数速度要慢一些。这是因为函数的参数和局部变量都是在系统的栈空间中进行保存的,每调用一次都会进行一次对这些变量的拷贝,这样就有可能导致栈空间被耗尽。如果这点确实发生了,那么数据就会被破坏。然而,在递归层次不是很深的情况下,我们没有必要担心这一点。
    使用递归的一个显著特点就是和对等的循环方式来比,一些算法采用递归则会更清晰和简单。例如,快速排序算法就很难用循环的方式来实现。另外,一些问题特别是和人工智能相关的问题采用的都是递归。
    在编写递归程序的时候,我们必须写上一个if这里的条件语句,来迫使函数不再递归调用就可以返回。如果不提供这样的条件语句,一旦函数被调用就永远不会返回。这也是一个常见的错误。当我们编写带有递归函数的程序的时候,我们可以有意地在其中加入cout语句以便观察程序的执行,一点发现错误就应该离开终止程序。下面是另外一个使用递归函数reverse()的程序,它把字符串参数逆序打印出来。

#include <iostream>using namespace std;void reverse( char *s);int main(){    char str[] = "this is a test";    reverse(str);    return 0;}//逆序打印字符串void reverse(char *s){    if (*s)        reverse(s+1);    else        return;    cout << *s;}
    函数reverse()先是检查传入的指针是否指向字符串的结束标志。如果不是,则递归调用reverse(),传入指向下一个字符的指针。最终当传入的是指向字符串结束标志的指针的时候,函数调用开始依次返回,字符串就被逆序打印出来。

    最后一点:递归对于初学者来说会比较难。虽然你可能目前对递归有点迷惑,但是请不要放弃。随着时间的推移,我们会越来越熟悉递归的。