C语言-递归的基础应用

*递归*

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

递归的两个必要条件

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

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

*迭代*

迭代的思路可能有时候不如递归简单,但是迭代的效率更高,更不容易造成栈溢出的情况,所以要合理应用递归和迭代

借用函数递归解决斐波那契,青蛙跳台阶,汉诺塔等经典问题,递归的思路就是把一个大的问题通过拆分成几个子问题来解决

*斐波那契数列*

求第几个斐波那契数是用递归解决问题的一个经典案例

斐波那契数列:1 1 2 3 5 8 13 21...,即从第三项开始每一项等于前面两项的和

即fib(n)=fib(n-1)+fib(n-2),n>2时成立,fib(n)=1,n<=2时成立,这就把一个大的问题拆分成了几个相似的子问题,代码实现如下

int Fib(int n)
{
	
    if (n <= 2)
	{
		return 1;
	}
	 else if (n > 2)
	{
		return Fib(n - 1) + Fib(n - 2);
	}
}
int main()
{
	printf("请输入你要求的第几个斐波那契数:\n");
	int Fib_number = 0;
	scanf_s("%d ", &Fib_number);
	int ret = Fib(Fib_number);
	printf("%d", ret);
	return 0;
}

拓展:

有时候用递归解决斐波那契问题会占用大量的栈帧空间,可能会造成栈溢出

所以我们可以考虑用迭代解决问题,代码如下:

int Fib(int n)
{
	if (n <= 2)
	{
		return 1;
	}
	else if (n > 2)
	{
		int a, b, c = 1;
		for (int i = 0;i < n - 2;i++)
		{
			b = c;
			a = b;
			c = a + b;
//将abc的相互调换,从而实现相邻两个数的和的求解
		}
		return c;
	}
}
int main()
{
	printf("请输入你要求的第几个斐波那契数:\n");
	int Fib_number = 0;
	scanf_s("%d ", &Fib_number);
	int ret = Fib(4);
	printf("%d", ret);
	return 0;
}

*青蛙跳台阶的问题*

假设这里有n阶台阶,然后青蛙每次只能跳一阶或者是两阶,请问有多少种跳台阶的方案

分析:我们定义一个jump函数,假设有jump次方案

当n<=2时,jump(n)=n.

当n>2时,在第一次跳台阶的时候,可以选择跳一阶,这个时候我们的跳的情况就是jump(n-1)次,也可以选择跳两阶,这个时候我们的次数就是jump(n-2)次,所以我们的总的次数为两者加起来

所以有jump(n)=jump(n-1)+jump(n-2),当n>2时(其实也就是斐波那契)代码如下

int jump(int n)
{
	if (n <= 2)
	{
		return n;
	}
	else if (n > 2)
	{
		return jump(n - 1) + jump(n - 2);
	}
}
int main()
{
	printf("请输入你要跳的台阶数:");
	int step_number = 0;
	scanf("%d ", &step_number);
	int ret = jump(step_number);
	printf("%d ", ret);
	return 0;
}

1ab3c4b1a188406aa2b8103fc7569cfc.png

d82555f105894968836d8d4b6583d9a7.png

上面是leetcode第70题爬楼梯问题,关于递归与迭代两种方法的优劣比较,可以发现,迭代法相比于递归法虽然思路略显困难,但是耗时和空间都要好于递归

*汉诺塔问题*(数学角度分析)

汉诺塔问题的描述网上的资料有很多,这里我们换一个角度分析,如果我们把挪动的次数想象成一个函数,所以就有函数表达式

f(x)=2f(x-1)+1,x>=2

f(x)=1,x=1

所以其实我们在前面说过,函数递归其实也可以类比成数列的相邻项的递推

所以如果用代码实现就是

#include<stdio.h>
int Hanoi_tower(int n)
{
	if (n < 2)
	{
		return 1;
	}
	else if (n >= 2)
	{
		return Hanoi_tower(n - 1) * 2 + 1;
//这个公式其实就是函数的递推式
	}
}
int main()
{
	int tower_number = 0;
	scanf_s("%d", &tower_number);
	int ret = Hanoi_tower(tower_number);
	printf("%d", ret);
}

那我们换一个角度思考,如何避开递推呢?在中学数学中我们学到过相邻两项数列的构造,

这个形式正好可以构造出一个新的数列,即f(x)+1=2*(f(x-1)+1),即f(x)+1可以类比成一个首项是4,公比为2的等比数列,求出f(x)的解析式,代码见下

#include<stdio.h>
#include<math.h>
int Hanoi_tower(int n)
{
	if (n < 2)
	{
		return 1;
	}
	else if (n >= 2)
	{
		return 4*pow(2,n-2)-1;
//即直接返回解析式算出来的值即可
	}
}
int main()
{
	int tower_number = 0;
	scanf_s("%d", &tower_number);
	int ret = Hanoi_tower(tower_number);
	printf("%d", ret);
}

谢谢观看!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值