递归


1.递归简介

C语言允许一个函数调用其本身。这种调用过程被称作递归。注意当一个函数调用自己时,如果编程中没有设定可以终止递归的条件检测,它会无限制地进行递归调用。

递归一般可以替代循环语句使用,有些情况下使用循环语句比较好,而有些时候使用递归更有效。递归方法虽然使程序结构优美,但其执行效率却没有循环语句高。

2.一个简单的递归示例

#include 

void func(int n)
{
    if (n > 0)
    {   
        printf("n = %d\n", n); 
        func(n - 1); 
        printf("n = %d\n", n); 
    }   
}

int main(void)
{
    func(5);

    return 0;
}

可以预见的结果是:

n = 5
n = 4
n = 3
n = 2
n = 1
n = 1
n = 2
n = 3
n = 4
n = 5

那么来简单分析一下这个递归程序的工作过程。 首先main函数中调用递归函数func,并传入参数5.
接着func(5)执行,由于5大于0,所以第一个printf执行,打印出5. 接着,func(4)执行,那么形参n在函数被第2次调用的时候被赋值为4,之后判断,第一个printf执行,打印出4.
同样的,下面的调用分别打印出3,2,1,当打印n=1后,执行func(0),此时n被赋值为0,则无法通过判断,func(0)执行结束返回被调用函数中,也就是func(1)中,现在函数继续执行,打印出n=1. 接着同样的打印出2,3,4,5.

注意:
每一级的递归都使用它自己私有的变量n.也可以通过查看变量的地址来得出这个结论。

3.递归的基本原理

  • 1.每一级的函数调用都有自己的变量。
  • 2.每一次函数调用都会有一次返回。当程序执行到某一级递归的结尾处时,它会转移到前一级递归继续执行。程序不能直接返回到main()中的初始调用部分,而是通过递归的每一级逐步返回,即从func()的某一级递归返回到调用它的那一级。
  • 3.递归函数中,位于递归调用前的语句和各级被调函数具有相同的执行顺序。
  • 4.递归函数中,位于递归调用后的语句的执行顺序和各个被调函数的顺序相反。
  • 5.虽然每一级递归都有自己的变量。但是函数代码并不会得到复制。函数代码是一系列的计算机指令。而函数调用就是从头执行相应函数的指令集,除了会每次创建变量,递归调用非常类似于一个循环语句。
  • 6.递归函数中必须包含可以终止递归调用的语句。

一个递归和循环比较的简单程序:

//递归
int mystrlen(const char *s, int n)
{
    if(s[n])
        return mystrlen(s, n + 1) + 1;
    else
        return 0;
}
//循环
int mystrlen2(const char *s) 
{
    int i = 0;

    while(s[i])
    {   
        i++;        
    }   

    return i;
}

这两个函数分别是用递归和循环来自己实现求字符串长度的功能,可以看到两者的区别,递归在此处的复杂度是大于循环的。只是做个演示,在此处是不适合用递归的。

4.递归的优缺点

使用递归既有优点也有缺点,其优点在于为某些编程问题提供了最简单的解决方法,比如二叉树的遍历,著名的斐波纳契数列。而缺点是一些递归算法会很快耗尽计算机的内存资源。同时,使用递归的程序难于阅读和维护。

你可能感兴趣的:(C,递归)