- 递归程序设计
- 题目分析
1.一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。
这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?
递归出口:经过的村子数为0
递归体:剩余的鸭子数目加以乘以2
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
递归体:若为偶数,则把它除以2,若为奇数,则把它乘以3加1。
- 算法构造
1. while (vil_num > 0)
{
return Duck_number1((count+1)*2,vil_num-1);
}
return count; //直接返回鸭子总数
2. while (number != 1) {
//偶数除以2奇数乘以3加1
if (number % 2 == 0){
number /= 2;
printf("%d ", number);
return Step_num1(number,step+1);
}
else{
number = number * 3 + 1;
printf("%d ", number);
return Step_num1(number,step+1);
}
}
return step; //返回步数
- 算法实现 (编程环境VS 2017)
-
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<windows.h> //非递归求鸭子总数 int Duck_number2(int count,int vil_num) { int sale = 0; for (; vil_num > 0; vil_num--) { count = (count + 1) * 2; sale = count / 2 + 1; printf("经过第%d个村庄时卖出的鸭子数为:%d\n", vil_num, sale); } return count; } //递归求鸭子总数 int Duck_number1(int count, int vil_num) { int sale = 0; //卖出的鸭子数 //递归终止条件村庄数为0 while (vil_num > 0) { count = (count + 1) * 2; sale = count / 2 + 1; printf("经过第%d个村庄时卖出的鸭子数为:%d\n", vil_num, sale); return Duck_number1(count, vil_num-1); } return count; } //递归算步数 int Step_num1(int number,int step) { //递归终止条件number为1 while (number != 1) { //偶数除以2奇数乘以3加1 if (number % 2 == 0){ number /= 2; printf("%d ", number); return Step_num1(number,step+1); } else{ number = number * 3 + 1; printf("%d ", number); return Step_num1(number,step+1); } } printf("\n"); return step; } //非递归算步数 int Step_num2(int number,int step) { for (step; number != 1; step++) { if (number % 2 == 0) { number /= 2; printf("%d ", number); } else { number = number * 3 + 1; printf("%d ", number); } } printf("\n"); return step; } int main() { //1.一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。这样他经过了七个村子后还剩两只鸭子, //问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子? int remainder = 2; //经过7个村子后剩的鸭子数 int village_number = 7; //经过的村子数 int count = 0; //鸭子总数 count = Duck_number1(remainder, village_number); //调用递归函数求鸭子总数 printf("(递归)出发时的鸭子总数为:%d\n", count); count = Duck_number2(remainder, village_number); //调用非递归函数求鸭子总数 printf("(非递归)出发时的鸭子总数为:%d\n", count); //2.角谷定理。输入一个自然数,若为偶数,则把它除以2,若为奇数,则把它乘以3加1。 //经过如此有限次运算后,总可以得到自然数值1。求经过多少次可得到自然数1。 int number = 0; //定义一个要计算角谷定理的自然数 int step = 1; //步数初始化为1 printf("请输入一个要计算角谷定理的自然数:"); scanf("%d", &number); step=Step_num1(number,step); //调用递归函数求步数 printf("递归 STEP=%d\n", step); int step_1 = 1; //非递归的步数初始化 step = Step_num2(number, step_1); //调用非递归函数求步数 printf("非递归 STEP=%d\n", step); system("pause"); return 0; }
- 调试,测试及运行结果
调试:
- 第一次将递归方法写错了地方,写在了递归出口的地方导致运行结果一直为第7个村庄前的鸭子数。
经过调试设置断点找出问题。
解决办法:递归方法应当放在第一个if里面。
2.非递归步数出错,调试发现因为第一次算完的STEP直接传入了第二次非递归函数的实参,导致STEP在非递归中初值为16;
解决办法:重新定义一个计算步数的变量传入第二个函数的实参,初值为1 。
测试代码:
1. while (vil_num > 0)
{
return Duck_number1((count+1)*2,vil_num-1);
}
return count; //直接返回鸭子总数
2. while (number != 1) {
//偶数除以2奇数乘以3加1
if (number % 2 == 0){
number /= 2;
printf("%d ", number);
return Step_num1(number,step+1);
}
else{
number = number * 3 + 1;
printf("%d ", number);
return Step_num1(number,step+1);
}
}
printf("\n");
return step; //返回步数
运行结果:
- 经验归纳
经过这张对递归的学习,发现了自己的很多不足,一定要理解好递归才不会约到很多问题。首先,做这类题要要读懂题目然后思考递归终止的条件和递归的体,将递归发法放在合适的位置才能输出正确结果并且一定要写递归出口否则程序将死循环。然后用合适的循环判断解决问题,并且小心局部变量的循环清零。在我刚开始写第一个鸭子题的时候刚开始遇到了很多问题,我没有弄清楚递归体的位置和循环条件就一直出错。后来改正后做第二个题就容易了,一定要想好题目做出递归后非递归就好实现了。