第六章上机报告
一.题目要求
(1)实验题目
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
(2)实验目的
- 掌握递归程序设计的方法。明确递归的概念,通过对问题的分析,找出递归关系以及递归出口以对问题进行递归结构设计;
- 掌握递归程序转换为非递归程序的方法。
二.问题分析
2.1 题目分析
(1)赶鸭子问题
①递归实现:
到达村庄village后剩余鸭子数(a)加上卖出鸭子数(num)等于所到村庄鸭子数之和(sum)。设经过村庄village后,剩余鸭子数为duck(),每到达一个村庄卖出鸭子数的一半又一只,则到达(village-1)村庄时,剩余鸭子数为2*(duck(village-1)+1)。设刚出发时,尚未经过村庄时的鸭子数为duck(7),经过了第七个村庄后剩余鸭子数为两只,也就是说在将要经过第八个村子时,剩余鸭子数为两只,即duck(0)=2.
递归函数体为
(duck(village)=2,village=0、
duck(village)=2*(duck(village-1)+1),0<village<8)
递归函数出口为duck(village)=2,village=0
递归函数体为duck(village)=2*(duck(village-1)+1),0<village<8
②非递归实现:
用for循环实现非递归的方法。定义村庄数为i,当前村庄卖出一半又一只鸭子后剩余鸭子总数为sum,当前村庄卖出鸭子数为num,当前所有鸭子总数为sums。 由题目知,当经过第七个村庄时sum=2,利用for循环实现i=7逐个递减计算出总共鸭子数sum。
(2)角谷定理问题
①递归实现
当输入值为1时,直接输出1,且输出step=1,所以step(1)=1,a=1。当输入值为偶数a且不为1时,先输出a的值,记录运算次数加一,实现递归函数step()=step(a/2)。当输入值为奇数且不为1时,先输出a的值,记录运算次数加一,实现递归函数step()=step(a*3+1)。键盘输入一个数,按以上方式进行逐步计算直到a的值为1时结束,打印输出step的值。
递归函数如下
(step()=a , a=1
step()=step(a/2),a%2=0
step()=step(a*3+1) a%2!=0)
函数出口为step()=a , a=1。
②非递归实现
用一个while循环来实现非递归调用,当满足条件a=1时,break跳出循环,否则一直进行运算,每进行一次运算step加一,直到跳出循环,输出step的值。
2.2详细实现
①赶鸭子递归实现
package 递归;
//递归实现买鸭子
public class duck {
public static int duck(int village) { //递归体实现
if(village==0)
return 2;
else if(village>0)
return 2*(duck(village-1)+1);
return village;
}
public static void main(String[] args) {
int i,num,a;
int sum=duck(7);//递归体调用,计算出总共的鸭子数sum
System.out.println(“总共有”+sum+“只鸭子!”);
a=sum;
for(i=1;i<8;i++) { //for循环输出每到达一个村庄剩余鸭子数和卖出鸭子数
num=a/2+1;
a=a-num;
System.out.println(“经过第”+i+“个村子时卖出”+num+“只鸭子,还剩下”+a+“只鸭子”);
}
}
②赶鸭子非递归实现
package 非递归;
public class duck {
public static void main(String[] args) {
int i,sums,num;
int sum=2;
for(i=7;i>0;i--) {
sums=(sum+1)*2;
num=sums-sum;
System.out.println("经过第"+i+"个村子时卖出"+num+"只鸭子,还剩下"+sum+"只鸭子");
sum=sums;
}
System.out.println("总共有"+sum+"只鸭子!");
}
}
③角谷定理递归实现
package 递归;
import java.util.Scanner;
/*角谷定理递归方法
* step为经历次数
* a为输入的自然数*/
public class 角股定理 {
static int step;
/*递归函数: step()=a a=1
* step()=step(a/2) a%2=0
* step()=step(a*3+1) a%2!=0
*/
public static int Step(int a) {
if(a==1) //输入的自然数为1
{
System.out.print(a+" ");
step++;
}
else if(a%2==0) //输入的自然数为偶数
{
System.out.print(a+" ");
Step(a/2); //调用递归方法
step++;
}
else if(a%2!=0) //输入的自然数为奇数
{
System.out.print(a+" ");
Step(a*3+1); //调用递归方法
step++;
}
return step;
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
System.out.print("请输入一个自然数:");
int a=sc.nextInt();
sc.close();
int step=Step(a);
System.out.println("\n一共经过了"+step+"次");
}
}
④角谷定理非递归实现
package 非递归;
import java.util.Scanner;
/*角谷定理非递归方法
* step为经历次数
* a为输入的自然数*/
public class 角股定理 {
static int step;
public static void main(String[] args) {
int i;
Scanner sc=new Scanner(System.in);
System.out.println("请输入一个自然数:");
int a=sc.nextInt();
sc.close();
while(a>0){
if(a==1) {
step++;
System.out.print(a);
break;
}
else if(a%2==0) {
step++;
System.out.print(a+" ");
a=a/2;
}
else {
step++;
System.out.print(a+" ");
a=a*3+1;
}
}
System.out.println("\n一共经历了"+step+"次");
}
}
三.调试及测试截图
(一)赶鸭子
(二)角谷定理
四.个人总结
(1)开始时对递归问题的递归出口和函数体不太熟悉,导致花费了较多的时间,最后通过反复思考查阅资料,对递归有了更加清楚的认识,递归问题要分解为若干个规模较小的与原问题形式相同的子问题,这些子问题可以用相同的解题思路来解决。
(2)通过递归与非递归方法的使用,让我进一步认识到递归方法的优势,递归方法相对于非递归的方法更加简洁好实现,很清晰的描述了算法的步骤,对于不知道循环次数的函数,调用递归求解具有更大的优势。
参考资料: https://blog.youkuaiyun.com/sinat_38052999/article/details/73303111