完全自学C(干货) —— 递归

递归 recursion

  • 程序调用自身的编程技巧,称为递归;
  • 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解;
  • 递归的策略只需少量的程序就可描述出解题过程所需的多次重复计算,大大减少程序的代码量;
  • 注意思想方式在于:大事化小;

必要条件

  • 存在限制条件,当满足这个限制条件的时候,递归将不在继续,否则无限调用;
  • 每次递归调用之后越来越接近这个限制条件;
//如n=1234,则打印1 2 3 4
void print(unsigned int n)
{
	if (n > 9)
		print(n / 10);
	printf("%d ",n % 10);
}
//编写函数不允许创建临时变量,求字符串的长度
int myStrlen(char* str)
{
    if ('\0' == *str) //限制条件
        return 0;
    else
        return 1 + myStrlen(str + 1); //越来越接近‘\0’
}
 
int main()
{
    char str[] = "abcd";
    printf("%d", myStrlen(str));
}

注:递归层次不要太深,否则也会出现栈溢出情况;因为每调用一次即开辟一块内存,如果调用次数过多,即会有可能造成栈溢出;

//递归方式
//n的阶乘
int factorial (int n) 
{
    if(n <= 1)
        return 1;
    else
        return n * factorial(n-1);
}
//注:求10000的阶乘时程序会崩溃;
//递归方式
//斐波那契
int fib(int n)
{
    if(n <= 2)
        return 1;
    else
        return fib(n - 1) + fib(n - 2);
}
//注:求50以上的斐波那契时,非常耗时,有可能栈溢出;

注:

  • 栈区,局部变量、函数形参;
  • 堆区,动态内存(malloc/calloc/realloc);
  • 静态区,全局变量、静态变量;

程序员的知乎:Stack Overflow - Where Developers Learn, Share, & Build Careers

解决办法

  • 将递归改写成非递归,如循环迭代;
  • 使用static对象替代nonstatic局部对象。在递归函数设计中,可以使用static对象替代nonstatic局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放nonstatic对象的开销, 而且static对象还可以保存递归调用的中间状态,并且可为各个调用层所访问;

提示:

  • 许多问题是以递归形式进行解释的,这只是因为它比非递归形式更为清晰;
  • 迭代实现往往比递归实现效率更高,但代码的可读性稍微差些;
  • 当一个问题相当复杂,难以迭代实现时,递归实现的简洁性可补偿运行时的开销;
//循环迭代方式
//n的阶乘
int factorial(int n)
{
    int result = 1;
    while (n > 1)
    {
        result *= n;
        n -= 1;
    }
    return result;
}
//循环迭代方式
//斐波那契
int fib(int n)
{
    int result;
    int prepre;
    int pre;

    result = pre = 1;
    while (n > 2)
    {
        n -= 1;
        prepre = pre;
        pre = result;
        result = prepre + pre;
    }
    return result;
}

案例

  • 汉诺塔问题
  • 青蛙跳台阶问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值