作者:无*
时间:2019-5-27
递归程序设计
一.题目分析
题目一:
一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?
递归算法:递归出口(num==0,num表示的是村庄数);递归表达式(duck(2*(sum+1),num-1)sum表示剩余鸭子数);先调用duck(2,7);可以求出鸭子总数,再在函数体内实现递归调用,最后求出每经过一个村庄所卖鸭子数。
非递归算法:调用此函数,函数体最后返回鸭子总数,函数体内通过一个for循环表示每经过一个村庄所卖鸭子数,主要变量有:最后剩余的鸭子数,所赶的鸭子数及所卖的鸭子数。
**主要算法规律总结:
所卖鸭子数=所赶鸭子数/2+1;
所赶鸭子数-(所赶鸭子数/2+1)=2 --------第7个村子
题目二:
角谷定理。输入一个自然数,若为偶数,则把它除以2,若为奇数,则把它乘以3加1。经过如此有限次运算后,总可以得到自然数值1。求经过多少次可得到自然数1。
递归算法:首先利用if语句判断奇数偶数,再通过判断数字是否为1,如果不为1,进行递归调用,继续判断,直至结果为一。其中还要设置一个STEP变量记录次数。
非递归算法:
通过while循环实现非递归算法,最后输出每一步的结果,并且输出执行次数STEP;
**主要算法
奇数和偶数的判断以及要执行的语句
判断偶数(num%2==0);
二.算法构造
题目一:
递归算法:
递归出口(num==0), 递归函数体:所赶鸭子数=2*(sum+1),此时村庄数num-1
如果满足递归出口条件则直接返回sum;否则进行递归调用。注意先利用一个函数调用计算出总的鸭子数,再利用一个for循环计算出所卖出的鸭子,本天所卖出的鸭子数=本天所赶鸭子数x/2+1;下一天的所赶鸭子数x=本天所赶鸭子数x/2-1;
非递归算法:
定义三个变量最后剩余的鸭子数remanent=2,所赶的鸭子数y=0及所卖的鸭子数sellnum=0;通过一个for循环计算出每一步的结果,for循环中的主要执行语句为:
所赶鸭子数y=2*(剩余鸭子数remanent+1);所卖鸭子数sellnum=所赶鸭子数y/2+1;
最后每一次还要更新剩余鸭子数remanent=y;(即上一天所剩余的鸭子数=这一天所赶的鸭子数);最后返回鸭子总数y.
题目二:
递归算法:
递归出口(num==1)
num=num/2(偶数) num=3*num+1(奇数);
如果不满足递归出口则实现递归调用jiaogu(num,STEP);
非递归算法:
利用while语句实现循环,多次调用。while语句的条件时(num!=1)输出每一步的结果,函数最后的返回值为STEP;
三.算法实现
(详细完整代码另附)
主要代码部分:
题目一:
递归部分:
public static int duck(int sum,int num) //sum表示鸭子数,num表示村庄数
{ if(num==0){ //递归出口
return sum;}
else{
return duck(2*(sum+1),num-1);
}
}
非递归部分:
public static int duck2()
{ int remanent=2;//最后剩余的鸭子数
int sellnum=0;//卖出的鸭子数
int y=0;//所赶的鸭子数
for(int j=1;j<8;j++)
{ y=2*(remanent+1);
sellnum=y/2+1;
remanent=y;
System.out.println("经过第"+(8-j)+"个村庄"+"卖出的鸭子数为"+sellnum);
}
return y;
}
题目二:
递归算法:
public static void jiaogu(int num,int STEP)
{
if(num%2==0) //num为偶数
{ num=num/2;
System.out.println(num);}
else if(num%2!=0&&num!=1) //num为奇数
{num=3*num+1;
System.out.println(num);}
STEP++; //STEP表示次数
if(num!=1)
jiaogu(num,STEP);
if(num==1)
{
System.out.println("STEP="+STEP);
}
}
非递归算法:
public static int jiaogu2(int num,int STEP)
{ while(num!=1)
{if(num%2==0) //num为偶数
{ num=num/2;}
else
{num=3*num+1; }
System.out.println(num);
STEP++;
}
return STEP;
}
四.调试,测试及运行结果
1.调试:
题目一:
题目2::
2.测试
题目一测试代码及截图:
public static void test1(int ducknum)
{for(int i=1;i<8;i++)
ducknum=ducknum/2-1;
if(ducknum==2)
System.out.println("代码正确,测试成功");
else
System.out.println("测试有误");
}
题目二:
3.运行结果
分别利用switch语句写了每个题目的递归算法和非递归算法
题目一:
递归算法:
非递归算法:
题目二:
递归算法:
非递归算法:
五.经验归纳
通过本次的上机题目,掌握了递归程序设计的方法,明确了递归的概念,通过对不同题目的分析,找出了递归的出口和对应的递归体。同时针对一个问题,还能有不同的思考方式,能将递归与非递归进行相应的转化。了解到了递归模型由递归出口和递归体两部分组成,前者确定递归何时结束,后者确定递归的方式。递归的应用在有些情况下能让程序更简洁易懂,改善程序的可读性。
在本次上机实验中,针对两个题目分别应用了递归算法和非递归算法,最后用了switch语句方便进行比较。通过本次上机,我总结了以下的方法:在递归程序的设计过程中,首先要进行正确的题目分析(如:用数学方法推导出递归公式等),可以先将自己的算法设计用普通方法编写出来。其次进一步就是设计大致的结构:递归的出口还有递归体分别是什么,最后再进行整合。