递归函数的设计技巧

1. 设计递归函数的步骤

1. 给递归函数一个明确的定义。
2. 实现边界条件时的程序逻辑。
3. 假设递归函数调用返回结果是正确的,实现本层函数逻辑。

2. 实战解析

1. 递归计算阶乘

解析:

这是一个比较简单的题目。现在按照上面的步骤进行解析:首先,明确递归函数的定义。这里我们给递归函数f(n)的定义就是返回n的阶乘。

然后,实现边界条件下的程序逻辑。这里很明显当n等于1时,就是边界条件,返回1的阶乘也就是1。

最后假设递归函数调用返回结果是正确的,实现本层函数逻辑。数学归纳法中的第三步是假设p(k-1)正确,证明p(k)正确。设计递归函数的第三步和这一步有着异曲同工之处。假设f(n-1)就是正确的返回n-1的阶乘,如何实现f(n)的阶乘呢?很简单的公式:f(n)=f(n-1)*n。至此,函数设计完成。

#include<iostream>

int f(int n)
{
	if (n == 1)
	{
		return 1;
	}
	return f(n - 1) * n;
}
int main()
{
	int a = f(4);
	std::cout << a << std::endl;
	return 0;
}

2. 路飞吃桃

题目描述

路飞买了一堆桃子不知道个数,第一天吃了一半的桃子,还不过瘾,又多吃了一个。以后他每天吃剩下的桃子的一半还多一个,到 n 天只剩下一个桃子了。路飞想知道一开始买了多少桃子。


输入

输入一个整数 n(2≤n≤30)

输出

输出买的桃子的数量。


样例输入1
2
样例输出1
4
样例输入2
3
样例输出2
10

解析:

按照上面的步骤分析:首先明确递归函数的参数以及返回值的意义,n代表剩一个桃子时是第n天。返回值是当第n天剩余一个桃子时,原来的桃子数。

接着,实现边界条件下的程序逻辑。显然,用例输入输出已经告诉了我们。

最后,假设返回值是正确的,实现本层逻辑。假如peachNum(n-1)是正确的,那peachNum(n)该如何计算?peachNum(n-1)是第n-1天剩余1个桃子时的原有桃子数,peachNum(n-1)和peachNum(n)的关系很好推导,peachNum(n)=(peachNum(n-1)+1)*2。

int peachNum(int n)//n天剩下一个桃子,返回原来的桃子数量2《=n《=30
{
	if (n == 2)
	{
		return 4;
	}
	return (peachNum(n - 1)+1)*2;
}
int main()
{
	int num;
	std::cin >> num;
	std::cout << peachNum(num);
	return 0;
}

3. 弹簧板

题目描述

有一个小球掉落在一串连续的弹簧板上,小球落到某一个弹簧板后,会被弹到某一个地点,直到小球被弹到弹簧板以外的地方。

假设有 n 个连续的弹簧板,每个弹簧板占一个单位距离,a[i]代表代表第 i个弹簧板会把小球向前弹 a[i]个距离。比如位置 11 的弹簧能让小球前进 22 个距离到达位置 33 。如果小球落到某个弹簧板后,经过一系列弹跳会被弹出弹簧板,那么小球就能从这个弹簧板弹出来。

现在小球掉到了11 号弹簧板上面,那么这个小球会被弹起多少次,才会弹出弹簧板。 11号弹簧板也算一次。


输入

第一个行输入一个 n代表一共有 n(1≤n≤100000)弹簧板。

第二行输入 n​ 个数字,中间用空格分开。第 i​ 个数字 a[i](0<a[i]≤30)​ 代表第 i个弹簧板可以让小球移动的距离。

输出

输出一个整数,表示小球被弹起的次数。


样例输入1
5
2 2 3 1 2
样例输出1
2
样例输入2
5
1 2 3 1 2
样例输出2
4

解析: 

我第一次做这题时并没有考虑递归,采用的是下面的解法。

step代表步长,distance记录小球弹跳的距离,m记录小球的当前位置。当小球弹跳的总距离小于弹簧板的个数时,步长+1并且更新弹跳距离和小球的位置,直到弹跳距离大于或等于板子个数。感觉这也是大部分同学的常规思路。

int spring(int n, int a[])
{
	int step = 0;
	int distance = 0;
	int m = 0;
	while (distance < n)
	{
		step++;
		distance += a[m];
		m += a[m];
	}
	
	return step;
}

下面我们试着用递归函数解决这道题目。

 首先,确定函数返回值的意义。i代表小球的当前位置,数组a代表弹簧板,num是弹簧板个数。函数返回值代表的是小球从i位置弹出弹簧板需要的步数。接着,实现边界条件下的程序逻辑。当小球的位置大于弹簧板个数时,就不需要加步数了。最后实现本层逻辑。当小球在i位置时,它弹出板子的步数可以由位置i+a[i]推导出。而从i位置到i+a[i]位置还需要弹一下,因此要加1。在初学阶段,不用考虑springRecursive(a+a[i])的值还没计算这一问题。只需要知道在springRecuresive(i+a[i])正确的情况下,springRecuresive(i)=springRecuresive(i+a[i])+1即可。

int springRecursive(int i,int a[],int num)
{
	if (i >= num)
	{
		return 0;
	}
	return springRecursive(i + a[i],a,num) + 1;
}

int main()
{
	int num;
	std::cin >> num;
	int *a=new int[num];
	for (int i = 0; i < num; i++)
	{
		std::cin >> a[i];
	}
	int res = springRecursive(0, a, num);
	std::cout << res << std::endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值