赶鸭子;角谷定理;java实现
- 题目分析
目的:
- 掌握递归程序设计的方法。明确递归的概念,通过对问题的分析,找出递归关系以及递归出口以对问题进行递归结构设计;
- 掌握递归程序转换为非递归程序的方法。
要求:
用递归方法设计下列各题,并给出每道题目的递归出口(递归结束的条件)和递归表达式。同时考虑题目可否设计为非递归方法,如果可以,设计出非递归的算法。
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
- 算法构造:
- 赶鸭子:
递归算法函数:duck()=2 Village=0
duck()=2*(duck(village-1)+1 0<village<8
非递归算法实现:
- 角谷定理:
递归算法函数:step()=a a=1
step()=step(a/2) a%2=0
step()=step(a*3+1) a%2!=0
非递归算法实现:
- 算法实现
- 赶鸭子:
递归实现:
package Duck;
//递归实现
/*village为村庄数
* sum为鸭子总数
* num为每经过一个村子卖出的鸭子数
* */
public class Duck递归 {
/*递归函数:duck()=2 village=0
* duck()=2*(duck(village-1)+1) 0<village<8
*/
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;
int sum=duck(7);
System.out.println("总共有"+sum+"只鸭子!");
for(i=1;i<8;i++) {
num=sum/2+1;
sum=sum-num;
System.out.println("经过第"+i+"个村子时卖出"+num+"只鸭子,还剩下"+sum+"只鸭子");
}
}
}
非递归实现:
package Duck;
/*非递归
* i为村庄数
* sums为当前村庄所有鸭子总数
* num为当前村庄卖出鸭子数
* sum为当前村庄卖出鸭子后所剩鸭子总数*/
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 角谷定理;
/*角谷定理递归方法
* step为经历次数
* a为输入的自然数*/
import java.util.Scanner;
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+"次");
}
}
- 调试、测试及运行结果
- 赶鸭子调试:
赶鸭子运行结果:
2. 角谷定理调试:
角谷定理运行结果:
- 经验归纳
1. 一开始在duck()递归函数中只在if语句中返回了值,在函数后没有返回形参,导致错误。
2. 在调试过程进入递归函数之中,一步步观察数值变化,对递归函数算法思路更加清楚。
3. 在duck非递归函数中将村庄数倒着输出,每一步输出后,将当前村庄鸭子总数nums作为上一个村庄卖出鸭子剩余数sum,直到第一个村庄后,直接输出sum即可,开始在循环外将sum与卖出鸭子数num相加作为鸭子总数,导致结果错误。