C语言中的 递归问题 以及将递归改写成非递归。(解析常见的几个递归题目及代码) 求阶乘、求斐波那契、汉诺塔、

目录

什么是递归?

递归的两个必要条件

一、接受一个整型值(无符号),按照顺序打印它的每一位。

二、递归求n的阶乘。

三、递归求斐波那契数

四、汉诺塔问题

五、将递归改写成非递归。


什么是递归?

程序调用自身的编程技巧称为递归( recursion)。 递归做为一种算法在程序设计语言中广泛应 用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复 杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可 描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。 递归的主要思考方式在 于:把大事化小

递归的两个必要条件

1.存在限制条件,当满足这个限制条件的时候,递归便不再继续。

2.每次递归调用之后越来越接近这个限制条件。

一、接受一个整型值(无符号),按照顺序打印它的每一位。

例如: 输入:1234,输出 1 2 3 4

#include<stdio.h>
int fun(int n)
{
    if(n > 9)
        {
            fun(n / 10);
        }
    printf("%d", n % 10);
       return 0;
}
int main()
{
     int num = 1234;
     print(num);
     return 0;
}

二、递归求n的阶乘。

#include<stdio.h>
 int fun(int n)
{
    if(1 == n)
    {
            return 1;
    }
    else
    {
        return n * fun(n -1);
    }
}
int main()
{
    int n, ret;
    scanf("%d", &n);
    ret = fun(n);
    printf("%d", ret);
    return 0;
}

三、递归求斐波那契数

    斐波那契数列1,1,2,3,5,8…,和卢卡斯数列1,3,4,7,11,18…,具有相同的性质:从第三项开始,每一项都等于前两项之和,我们称之为斐波那契—卢卡斯递推。凡符合斐波那契—卢卡斯递推的数列就称为斐波那契—卢卡斯数列。

求第n个斐波那契数。(不考虑溢出)

#include<stdio.h>
int fun(int n)
{
    if(1 == n  || 2 == n)
        {
            return 1;
        }
    else
        {
            return fun(n -1) + fun (n - 2);
        }
}
int main()
{
    int n, ret;
    scanf("%d", &n);
    ret = fun(n);
    printf("%d", ret);
    return 0;
}

四、汉诺塔问题

相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如图1)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。

#include<stdio.h>


int hannuota(int n, char Scr, char Dst, char Tmp)  //这个函数的意思是,由A座经过B座到达C座
{
	if (1 == n)                                        //n代表由n层塔
	{
		printf("%c -> %c\n", Scr, Dst);    //如果只有一层,直接从A挪到C,完成任务
	}
	else
	{
		hannuota(n - 1, Scr, Tmp, Dst);   //超过一层,那么问题可以看作是把他n-1层,从A挪到B
		printf("%c -> %c\n", Scr, Dst);    //再把剩下那一层,从A挪到C;
		hannuota(n - 1, Tmp, Dst, Scr);  //再把那n-1层从B挪到C,完成任务
	}                                     //任务不断由n-1简化
	return 0;
}
int main()
{
	int n;
	char TA = 'A';      //ABC分别代表三个台子
	char TB = 'B'; 
	char TC = 'C';
	scanf("%d", &n);
	hannuota(n, 'A', 'B', 'C');
	return 0;
}

运行程序,输入3,代表我们要挪动三层汉诺塔,我们得到三层汉诺塔的挪动顺序。 

 

五、将递归改写成非递归。

通过练习上面两个问题我们发现:

在使用 fun 这个函数的时候如果我们要计算第50个斐波那契数字的时候特别耗费时间。

使用fun 函数求10000的阶乘(不考虑结果的正确性),程序会崩溃。

为什么?

在调试 fun函数的时候,如果你的参数比较大,那就会报错: `stack overflow(栈溢 出) 这样的信息。 系统分配给程序的栈空间是有限的,但是如果出现了死循环,或者(死递 归),这样有可能导致一直开辟栈空间,最终产生栈空间耗尽的情况,这样的现象我们称为栈溢 出。

如果出现这样的问题,我们可以. 使用static对象替代nonstatic局部对象。

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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值