函数的递归

.目录

一、什么是递归? 

递归的思想:

二、递归的限制条件

三、递归的举例

递归求n的阶乘

顺序打印整数的每一位

四、递归与迭代

顺序打印整数每一位在内存空间中的演示:

迭代实现n的阶乘:

求斐波那契数列:

青蛙跳台阶问题:

汉诺塔问题:


一、什么是递归? 


!!!递归就是函数自己调用自己!!!

#include <stdio.h>
int main()
{
    printf("hehe\n");
    main();                      //main函数中⼜调⽤了main函数
    return 0;
}
//这里只是做一个简单的示例,这种写法是错误,会使程序陷入死递归导致Stack overflow(栈溢出)。

递归的思想:

把⼀个⼤型复杂问题层层转化为⼀个与原问题相似,但规模较⼩的⼦问题来求解;直到⼦问题不能再被拆分,递归就结束了。所以递归的思考⽅式就是把⼤事化⼩的过程。
递归中的递就是递推的意思,归就是回归的意思。



二、递归的限制条件

① 递归存在限制条件,当满⾜这个限制条件的时候,递归便不再继续。
② 每次递归调⽤之后越来越接近这个限制条件。



三、递归的举例

递归求n的阶乘

int Fun(int n)
{
	if (n <= 1)
		return 1;
	else
		return n*Fun(n - 1);
}

int main()
{
	int n;
	printf("请输入所要求的阶乘:");
	scanf_s("%d", &n);
	int count = Fun(n);
	printf("该数字的阶乘为:%d", count);
	return 0;
}

//画图演示

递推过程:

Fun(5) ------>   Fun(4)   ------> Fun(3)  ------>  Fun(2) ------>  Fun(1)  

=5*Fun(4)        =4*Fun(3)       =3*Fun(2)         =2*Fun(1)       =1  

                                                                                                                  |||

回归过程:                                                                                                |||

                                                                                                                  V

Fun(5) <------   Fun(4)  <------   Fun(3)  <------ Fun(2)<------- Fun(2)=120                                                                                                                            =2

顺序打印整数的每一位

void Print(int n)
{
	if (n > 9)
	{
		Print(n / 10);
	}

	printf("%d ", n % 10);
}

int main()
{
	int m = 0;
	printf("请输入要打印的数字:");
	scanf_s("%d", &m);
	printf("最终结果为:");
	Print(m);
	return 0;
}




四、递归与迭代

        对于上述的Fun函数是可以产⽣正确的结果,但是在递归函数调⽤的过程中涉及⼀些 运⾏时的开销
在C语⾔中每⼀次函数调⽤,都要需要为本次函数调⽤在栈区申请⼀块内存空间来保存函数调⽤期的各种局部变量的值,这块空间被称为 运⾏时堆栈 ,或者 函数栈帧
函数不返回,函数对应的栈帧空间就⼀直占⽤,所以如果函数调⽤中存在递归调⽤的话,每⼀次递归 函数调⽤都会开辟属于⾃⼰的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。 所以如果采⽤函数递归的⽅式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能 引起栈溢 出(stack over flow)的问题

顺序打印整数每一位在内存空间中的演示:


!!!递归层次不能太深,太深就会出现栈溢出的问题!!!

所以如果不想使⽤递归就得想其他的办法,通常就是迭代的⽅式(通常就是循环的⽅式)

迭代实现n的阶乘:

int Fact(int n)
{
	int i = 0;
	int j = 1;
	for (i = 1; i <= n; i++)
	{
		j *= i;
	}
	return j;
}

int main()
{
	int n;
	printf("请输入所要求的阶乘:");
	scanf_s("%d", &n);
	int count = Fact(n);
	printf("该数字的阶乘为:%d", count);
	return 0;
}
        事实上,我们看到的许多问题是以递归的形式进⾏解释的,这只是因为它⽐⾮递归的形式更加清晰, 但是这些问题的迭代实现往往⽐递归实现效率更⾼。 当⼀个问题⾮常复杂,难以使⽤迭代的⽅式实现时,此时递归实现的简洁性便可以补偿它所带来的运⾏时开销。

求斐波那契数列:

斐波那契数列:1  1  2  3  5  8  13 21 24......

#include <stdio.h>
int count = 0;
int Fid(int n)
{
	if (n <= 0)
		return 0;
	else if (n == 1)
		return 1;
	else
		count++;
		return Fid(n - 1) + Fid(n - 2);
	
}

int main()
{
	int n = 0;
	printf("请输入要求第几个斐波那契数列中的数字:>");
	scanf_s("%d", &n);
	int ret = Fid(n);
	printf("该数字为:%d\n", ret);
	printf("需要计算的次数为: %d\n", count);
	return 0;
}

但是如果是要求第40个斐波那契数呢?

很明显在我们求第四十个斐波那契数的时候第三个斐波那契数将会被计算165580140次,这个数字太大了计算这个数所需要的内存空间也会很大不划算。

所以我们可以直接通过迭代来实现求解斐波那契数列:

#include <stdio.h>
int count = 0;
int Fun(int n)
{
	int a = 1;
	int b = 1;
	int c = 1;
	while (n > 2)    //当n>2时开始进行循环相加
	{
		c = a + b;
		a = b;
		b = c;
		count++;
			n--;
	}
	return c;      //当n<2时直接输出1

}

int main()
{
	int n = 0;
	printf("请输入要求第几个斐波那契数列中的数字:>");
	scanf_s("%d", &n);
	int num = Fun(n);
	printf("该数字为:%d\n", num);
	printf("所需要的次数为:%d",count);
	return 0;
}

很明显用迭代来解决该问题运算次数明显减少。

青蛙跳台阶问题:

一、问题描述

        有一只🐸,一次可以跳一个台阶,也可以跳2个台阶,如果有n个台阶,这只🐸有多少种跳法,跳上n个台阶?

二、问题分析     

       第一次跳有两种情况:

             1)当第一次跳一个台阶时: 剩余台阶数为n-1

             2)当第一次跳两个台阶时: 剩余台阶数为n-2

       所以当n>2时,跳法总数=第一次跳一个台阶之后的跳法数+第一次跳两个台阶之后的跳法数

       而对于n=2或者n=1时,显然易见此时的跳法总数固定,分别为2或1。

       tips:对于后者我们只需要进行简单的if判断即可。

int Jump(int n)
	{
	if (n == 2)
		return 2;
	else if (n == 1)
		return 1;
	else if (n > 2)
	{
	int	count = Jump(n - 1) + Jump(n - 2);
	return count;
	}

	}


int main()
{
	int n;
	printf("青蛙要跳跃的台阶总数为:>");
	scanf_s("%d", &n);
	int count = Jump(n);
	printf("青蛙跳完所有台阶的方法总数为:%d", count);
}


汉诺塔问题:

一、问题描述 

                将A柱上的盘子,借助于B柱,全部挪到C柱子上,挪动过程中A,B,C柱上的盘子要满足上面小下面大

 二、问题分析

1)如果A只有一层:A(1)---->C(1)     1次移动

 大概就是这么个意思,下面的两种就不再演示了

2)如果A有两层:A----->B      A----->C     B----->C     3次移动

3)如果A有三层:A----->C    A----->B    C----->B    A------>C    B----->A   B----->C  A----->C  7次移动

4)如果A有n层:2^n-1  次移动

具体代码实现如下:

#include <stdio.h>
void move(char pos1, char pos2)
{
	printf("%C ->%c ", pos1, pos2);
}

//n代表盘子的个数
//pos1:起始位置
//pos2:中转位置
//pos3:目的位置

void Hanoi(int n, char pos1, char pos2, char pos3)   //主运行的
{
	if (n == 1)      //如果初始位置只有一个方块就直接把它移到目的位置即可
	{
		move(pos1, pos3);
	}
	else
	{
		Hanoi(n - 1, pos1, pos3, pos2);
		move(pos1, pos3);
		Hanoi(n - 1, pos2, pos1, pos3);
	}

}

int main()
{
	Hanoi(1, 'A', 'B', 'C');
	printf("\n");
	Hanoi(2, 'A', 'B', 'C');
	printf("\n");
	Hanoi(3, 'A', 'B', 'C');
	printf("\n");
}

~over~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值