递归程序设计方法及实例

 

 

                                                                                                递归程序设计方法及实例

 

 

    实例1:一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?

 

//卖鸭子
#include<stdio.h>
int num(int sum,int day);
int main()
{
	int s=num(2,8);                         //第七天还剩余鸭子2只
	printf("鸭子总数为%d只\n\n",s);
	for(int day=1;day<=7;day++)             //输出每天卖出的鸭子数
	{
		printf("第%d天卖出%d只\n",day,s/2+1);
		s=s/2-1;
	}
	return 0;
}
int num(int sum,int day)
{
	if(day==1)
		return sum;
	else
		return num((sum+1)*2,day-1);        //递归计算鸭子数
	return 0;
}

 

   实例2:角谷定理。输入一个自然数,若为偶数,则把它除以2,若为奇数,则把它乘以3加1。经过如此有限次运算后,总可以得到自然数值1。求经过多少次可得到自然数1。

如:输入22,

输出 22 11 34 17 52 26 13 40 20 10 5 16 8 4 1

 

//角谷定理
#include<stdio.h>
int step;
int calculate(int a);
int main()
{
	int a;                       //输入的自然数a
	printf("请输入一个自然数:");
	scanf("%d",&a);  
	calculate(a);
	return 0;
}
int calculate(int a)
{
	printf("%6d",a);
	if(a==1)
		printf("\nStep is %d\n",step+1);
        else
	{
	 	if(a%2==0)           //输入的自然数为偶数
		{
			a=a/2;
			step++;          //每计算一次,step加1
			calculate(a);    //递归调用
		}
		else if(a%2!=0)      //输入的自然数为奇数
		{
			a=a*3+1;
			step++;
			calculate(a);
		}
	}
	return 0;
}	if(a%2==0)           //输入的自然数为偶数
		{
			a=a/2;
			step++;          //每计算一次,step加1
			calculate(a);    //递归调用
		}
		else if(a%2!=0)      //输入的自然数为奇数
		{
			a=a*3+1;
			step++;
			calculate(a);
		}
	}
	return 0;
}

           实例三:电话号码对应的字符组合:在电话或者手机上,一个数字如2对应着字母ABC,7对应着PQRS。那么数字串27所对应的字符的可能组合就有3*4=12种(如AP,BR等)。现在输入一个3到11位长的电话号码,请打印出这个电话号码所对应的字符的所有可能组合和组合数。

 

 

//电话号码对应字符组合
//假设此程序中,0和1对应的英文字母分别为'*','#'
//做出此假设的原因是因为0和1没有对应的英文字母
#include<stdio.h>
#define M 12
#define N 30
int a[M];               //a[M]存储电话号码每位上的数字
char b[28]={'*','#','A','B','C','D','E','F','G','H','I','J','K','L','M','N',
'O','P','Q','R','S','T','U','V','W','X','Y','Z'}; //b[M]存储每个数字对应的不同的英文字母
char c[10][10] = {      //用字符数组存储每个数字对应的不同英文字母
    '*', '#', "ABC", "DEF",
    "GHI", "JKL", "MNO",
    "PQRS", "TUV", "WXYZ"};
int i,n;
int GroupNum(int x); 
int main()
{
	printf("请输入电话号码的总位数:");
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		printf("请输入电话号码的第%d位:",i+1);
		scanf("%d",&a[i]);
	}
	i=0;
	printf("此电话号码对应的字符串组合共有%d组\n",GroupNum(1));
	return 0;
}
int GroupNum(int x)       //求总共组合数
{
	if(i==n)
		return x;
	else
	{
		if(a[i]==0 || a[i]==1)       
		{
			x=1*x;
			i++;
			GroupNum(x);  //递归调用  
		}
		else if(a[i]==2 || a[i]==3 || a[i]==4 || a[i]==5 || a[i]==6 || a[i]==8 )  
		{
			x=3*x;
			i++;
			GroupNum(x);
		}
		else
		{
			x=4*x;
			i++;
			GroupNum(x);
		}
	}
}

         实例4:日本著名数学游戏专家中村义作教授提出这样一个问题:父亲将2520个桔子分给六个儿子。分完 后父亲说:“老大将分给你的桔子的1/8给老二;老二拿到后连同原先的桔子分1/7给老三;老三拿到后连同原先的桔子分1/6给老四;老四拿到后连同原先的桔子分1/5给老五;老五拿到后连同原先的桔子分1/4给老六;老六拿到后连同原先的桔子分1/3给老大”。结果大家手中的桔子正好一样多。问六兄弟原来手中各有多少桔子?

 

 

//分桔子问题
#include<stdio.h>
// oldUNum为每个人原有桔子数,getNum为得到的桔子数,n为第几个人
int orangeNum(int oldNum,int getNum,int n);
int main()
{
	//老大原有240个桔子,得到210个
	orangeNum(240,210,1);
	return 0;
}
int orangeNum(int oldNum,int getNum, int n)
{
	int nextGetNum,nextOldNum,m;    
	if(n > 6)      //递归出口
		return 0;
        else
	{
		printf("     第%d个人原有桔子%d\n",n,oldNum);  //输出原先橘子数
                if(n == 1)                                     //计算分给下一个人的橘子数
			nextGetNum = oldNum/(9 - n);
                else
             		nextGetNum = (oldNum+getNum)/(9-n);
        	nextOldNum = 2520/6* (8-n)/(7-n) - nextGetNum;  //下一个人原来的橘子
       	 	m = n+1;
        	orangeNum(nextOldNum,nextGetNum,m);
        }
	return 0;
}

	nextGetNum = oldNum/(9 - n);
                else
             		nextGetNum = (oldNum+getNum)/(9-n);
        	nextOldNum = 2520/6* (8-n)/(7-n) - nextGetNum;  //下一个人原来的橘子
       	 	m = n+1;
        	orangeNum(nextOldNum,nextGetNum,m);
        }
	return 0;
}

                                                                      递归程序设计方法总结

 

 

                                                                                                                                                 ————常见递归问题的分析与设计

       1.卖鸭子问题:这是常见的递归函数问题,求得一个递归函数公式即可。设计函数int num( int sum,int day);其中sum参数返回鸭子的数量,day参数返回第几天。编写递归程序的关键为确定递归出口和递归体。本题递归出口为当day==1时,return sum;递归体为当day!=1时,return num((sum+1)*2,day-1);同时在主函数中输出每天所卖的鸭子数目。

       2.角谷定理:本题的设计思路比较简单,仍然为一个递归函数问题。按照题意,输入一个自然数,若为偶数,则把它除以2,若为奇数,则把它乘以3加1。经过如此有限次运算后,总可以得到自然数值1。得到递归结束出口为a==1;return总步数。递归体为当a==偶数时,自身除以二,并累加步数,返回calculate函数。当a为奇数时,自身乘三加一,并累加步数,返回calculate.

      3.电话号码对应的字符组合:首先清楚2,3,4,5,6,8六个数字对应三个英文不同的字母,8,9三个数字对应4个不同的英文字母。由于数字1和0并没有对应的英文字母,所以假设0和1分别对应’*’,’#’,这种假设并不影响最后递归算法的设计。还可以增强程序的健壮性。

      计算组合数:需要统计电话号码有几个数字,且每个数字对应几个英文字母。把每个数字对应的英文字母个数乘起来即为组合数。

      计算具体的组合:需要统计具体哪几个数字,每个数字具体对应的英文字母是什么。逐一进行组合即可。

      4.中村义作教授分桔子问题:这是一个环状互相关联的问题,想到应该使用递归来求解。首先应该分析得到已知和隐含条件。

最后桔子数目相等,则每人为420个。同时老大的身份最特殊,其余的人都是先得到再给出桔子,而老大是先给出后得到,并且最后为420个,由老六分给他210个桔子,则老大原来有240个桔子,老大原先有240个桔子,分出210个桔子,问题的突破口就找到了。设计函数orangeNum(oldNum,getNum,n);三个参数分别为原有桔子数,得到桔子数,和第几个人。将240,210,1三个参数传入后,就开始了递归函数的调用,当n>6时,递归调用结束。

       递归问题总结:递归是程序直接或者间接调用自身的过程,递归模型由递归出口和递归体两部分组成,分析问题时主要要抽象出递归出口和递归体。递归问题一般分为两大类:一类是比较简单的数学上的递归函数,要求算得一个函数值,只需要将递归函数翻译出来即可。第二类为问题为一些实际的问题,没有统一的规律可循,解决问题的关键为充分的理解问题,发现问题中的已知和隐含条件。根据逻辑关系分析此问题为什么为一个递归问题,并由此得到递归出口和递归递归体,从而使问题得到解决。这类问题都比较复杂,需要进行大量的练习才能建立这种思维方式。

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值