递归问题

一.实验目的
掌握递归程序设计的方法。明确递归的概念,通过对问题的分析,找出递归关系以及递归出口以对问题进行递归结构设计;
掌握递归程序转换为非递归程序的方法。
二 .实验内容
用递归方法设计下列各题,并给出每道题目的递归出口(递归结束的条件)和递归表达式。同时考虑题目可否设计为非递归方法,如果可以,设计出非递归的算法。
1.一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?
2.角谷定理。输入一个自然数,若为偶数,则把它除以2,若为奇数,则把它乘以3加1。经过如此有限次运算后,总可以得到自然数值1。求经过多少次可得到自然数1。
如:输入22,
输出 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
STEP=16
三.实验过程
1.题目分析
递归的主要思想是把大问题转化为一个小问题和一些常量,虽然小问题还没有解决,但已经向目标靠近了一步,这是一个“量变”,当到达递归的出口时,便发生了“质变”,递归问题就解决了。所以,问题在于如何将碰到的问题转化,确定“大问题”和“小问题”以及之间的联系,最后找到递归出口,问题就迎刃而解了,有了以上理解,对这两个问题具体分析一下。
1.1 求鸭子数量
大问题是求在经过某一个村子前有多少鸭子,小问题是经过上一个村子有多少鸭子,他们之间的联系是:这个村子=(后个村子+1)*2,同时在第七个村子时的鸭子很容易得出6只,但这样存在一个,递归公式是往后递归的,得不到结果,所以需要处理一下,将过程反过来看,问题变为到第7个村子鸭子有6只,要求前面的村子有多少鸭子,则:这个村子=(前村子+1)*2。
这个问题非递归也可以解决,任然从第七个村子往前看,经过每个村子前可以大致排一下:
… 30 14 6 2(最后剩下)。
可以看出,要求某一个村子对应的鸭子数,只需要在6的基础上进行加1再乘以2的多次运算即可,运算次数为7-村子序号+1。
1.2 角谷定理
大问题是求一个数经过特定操作变为1的操作次数,小问题是这个数过一次变换得到的数还需要操作多少次,他们之间的关系是前者等于后者加1,递归出口时当这个数等于2时,变换次数为1,这也是操作次数与具体数之间的联系。
从非递归的角度看,也能解决,只需要构建无限循环,结束条件为数等于1,在函数体对数进行对应的操作同时定义累加器记录操作数即可。
2.算法构造
2.1 经过上面对的分析,容易得出数学表达式如下:
递归调用函数:
在这里插入图片描述

非递归调用流程图: 在这里插入图片描述

2.2 角谷定理
递归调用
在这里插入图片描述

非递归调用
在这里插入图片描述
3.算法实现
3.1 鸭子

package RecursionProgram;

public class test1 {
	public static int question1_recursion(int x) {
		if(x==1)
			return 6;
		else return ((question1_recursion(x-1)+1)*2);
	}
	public static int question1_norec(int x) {
		int sum=6;
		for(int i=0;i<(7-x);i++) {
			sum=2*(sum+1);
		}
		return sum;
	}
	public static void main(String[] args) {
/*		递归解法
		System.out.println("出发时赶了"+question1_recursion(7)+"只鸭");
		for(int x=7;x>1;x--) {
			System.out.println("第"+(7-x+1)+"个村庄卖了"+(question1_recursion(x)-question1_recursion(x-1))+"只鸭");			
		}
		System.out.println("第7个村庄卖了"+(question1_recursion(1)-2)+"只鸭");
*/
		//非递归解法
		System.out.println("出发时赶了"+question1_norec(1)+"只鸭");
		for(int x=1;x<7;x++) {
			System.out.println("第"+x+"个村庄卖了"+(question1_norec(x)-question1_norec(x+1))+"只鸭");			
		}
		System.out.println("第7个村庄卖了"+(question1_norec(7)-2)+"只鸭");
		
	}
}

3.2 角谷定理

package RecursionProgram;

public class test2 {
	public static int question_recurtion(int x) {
		if(x==2)
			return 1;
		else if(x%2==0)
			return question_recurtion(x/2)+1;
		else return question_recurtion(x*3+1)+1;
	}
public static int question_norec(int x) {
	int count = 0;	
	while(x!=1) {
			if(x%2==0) {
				x=x/2;
				count++;
			}
			else {
				x=x*3+1;
				count++;
			}
		}
	return count;
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//System.out.println(question_recurtion(22));
		System.out.println(question_norec(22));
	}

}

4.调试、测试及运行结果
4.1 鸭子问题
在这里插入图片描述

4.2 角谷定理
在这里插入图片描述

5.经验归纳
递归问题重点在于问题的抽象以及划分,找到问题的大问题和小问题,找出他们之间的联系,个人感觉这是最难的部分,最后的递归出口不难找到,解决这3个点列出数学函数表方式,相应的编程就容易多了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值