一、实验目的
- 掌握递归程序设计的方法。明确递归的概念,通过对问题的分析,找出递归关系以及递归出口以对问题进行递归结构设计;
2.掌握递归程序转换为非递归程序的方法。
二、实验内容
用递归方法设计下列各题,并给出每道题目的递归出口(递归结束的条件)和递归表达式。同时考虑题目可否设计为非递归方法,如果可以,设计出非递归的算法。
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)赶鸭子问题:①递归:假设经过n个村庄时有fun(n)只鸭子,卖出去fun(n)/2+1只,剩余fun(n+1)只,当经过第八个村庄的时候剩余2只,即fun(8)=2,因此,刚开始有fun(1)只鸭子。该问题的递归出口为:fun(8)=2 n=8
函数体为:fun(n)=2*(fun(n+1)+1) 1<=n<8
fun(n)=2 n=8
②非递归:鸭子最后剩余2只,由公式left-(left/2+1)=dunk得出left=2*(dunk+1)卖出去的鸭子数为(left/2+1),利用循环计算出鸭子的总数,并输出。
(2)角谷定理:①递归:输入一个自然数,采用if语句判断该自然数是偶数还是奇数,若为偶数,则进行除2的操作,否则进行*3+1d 操作,该递归程序中
递归出口为:data=1
函数体为:Num1(data)=1 data=1
Num1(data)=Num1(data/2) data>1且data为偶数
Num1(data)=Num1(data*3+1) data>1且data为奇数
②非递归:采用while循环语句,判断该自然数是否是偶数,若是偶数则进行除2 操作,否则进行(*3+1)操作,当自然数为1时,停止循环,并输出次数。
2.算法构造
(1)赶鸭子问题:递归:
递归出口为:fun(8)=2 n=8
函数体为:fun(n)=2*(fun(n+1)+1) 1<=n<8
fun(n)=2 n=8
(2)角谷定理:
递归出口为:data=1
函数体为:Num1(data)=1 data=1
Num1(data)=Num1(data/2) data>1且data为偶数
Num1(data)=Num1(data*3+1) data>1且data为奇数
3.代码
package Recursion;
import java.util.Scanner;
public class Recursion {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int flag=1;
while(flag!=0){
int t;
System.out.println("请选择");
System.out.println("0----赶鸭子问题(递归方法) 1----赶鸭子问题(非递归) 2----角谷定理(非递归) 3----角谷定理(递归)");
Scanner sc=new Scanner(System.in);
t=sc.nextInt();
if(t==0){
int acount=fun(1);//刚开始鸭子的总数
int num=0;//卖出的鸭子数
System.out.println("出发时共有"+acount+"只");
for(int i=1;i<8;i++){
num=fun(i)/2+1;
System.out.println("经过第"+i+"个村子共卖出"+num+"只");
}
}
else if(t==1){
int num;
num=fun1();//刚开始鸭子总数
System.out.println("刚开始有"+num+"只鸭子");
}
else if(t==2){
System.out.println("请输入一个自然数");
int m;
//Scanner sc=new Scanner(System.in);
m=sc.nextInt();
Num(m);//调用递归函数Num()
}
else{
int step;
int data;
System.out.println("请输入一个自然数");
//Scanner sc=new Scanner(System.in);
data=sc.nextInt();
step=Num1(data,1);//调用非递归函数Num1()统计次数,并输出
System.out.println("经过"+step+"次");
}
System.out.println("请选择是否继续:0---no 1---yes");
flag=sc.nextInt();
if(flag==0)
System.out.println("程序执行完毕!");
}
}
//赶鸭子(递归)
public static int fun(int sum){
if(sum==8){//递归出口,当sum=8时
return 2;
}
else{
return 2*(fun(sum+1)+1);//返回鸭子的数量
}
}
//赶鸭子(非递归)
public static int fun1(){
int dunk=2;//最后剩余的鸭子数
int sale=0;//卖出去的鸭子数
int left=0;//剩余的鸭子数
//System.out.println("")
for(int i=0;i<7;i++){
left=2*(dunk+1);//计算剩余的鸭子数
sale=left/2+1;//计算卖出去的鸭子数
dunk=left;//更新剩余的鸭子数
System.out.println("第"+(7-i)+"个村子卖出"+sale+"只鸭子");
}
return left;//返回鸭子总数
}
//角谷定理(递归)
public static int Num1(int data,int step){
if(data==1){//递归出口,桑data=1时
System.out.println(data);
return step;
}
else if(data%2==0){//判断data是否是偶数
System.out.println(data);
data=data/2;//若是偶数则除以2
step++;//次数+1
return Num1(data,step);//调用递归函数Num1()
}
else {
System.out.println(data);
data=data*3+1;//若data是奇数,则*3+1
step++;//次数+1
return Num1(data,step);//调用递归函数Num()
}
}
//非递归
public static void Num(int num){
int step=1;
while(num!=1){
if(num%2==0){//判断num是否是偶数,若是则进行相应的操作
num=num/2;
}
else{//判断num是否是奇数,若是则进行相应的操作
num=num*3+1;
}
step++;//次数+1
System.out.println(num);//输出每次操作后的num
}
System.out.println("经过"+step+"次");//输出总次数
}
}
4.调试和运行代码
(1)调试
(2)运行
5.经验归纳
本次上机的目的在于掌握递归程序设计的方法和掌握递归程序转换为非递归程序的方法,两个问题都用到了递归方法和非递归方法,在编写程序的过程中也比较了两种方法,感觉递归相对来说比较简单一些,并且步骤相对来说也是比较少的,不过在采用递归方法解决问题时,最重要的便是找到递归的出口和写出函数体,只要找到了这两个,那么递归方法还是很简单的,递归方法很适合解决比较复杂并且步骤比较多的问题。而非递归方法只要顺着思路来就好了,在某些步骤上可能要比递归方法麻烦一点,不过对于解决比较简单的问题时,可以采用非递归方法。