递归算法实例(C++)

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

题目分析:经过7个村子后他还剩2只鸭子,而每经过一个村子卖出所赶鸭子的一半多一只,所以在经过第七个村子前他所赶的鸭子数为(2+1)*2=6只,经过第7个村子时卖出6/2+1=4只。设经过7个村子之后,即在经过第8个村子之前,village=7,duck=2,即f(7)=2。f(6)=(f(7)+1)*2,卖出f(6)/2+1只。以此类推,可得出他出发时的鸭子数以及经过每个村子卖出鸭子数。

算法分析:数学公式

f(x)表示经过x村子后剩余的鸭子数,出发前的总数count=((f(1)+1)*2)。

算法实现:

for  (village = 0; village<7; village++)//经过7个村庄

count = (duck + 1) * 2;//每经过一个村庄之前剩余的鸭子数量

duck = count;//将值传给dcuck,获得最终鸭子数,实现递归

当village=7时是递归出口。

源代码:

/*
File Name:duck.cpp
Author:
Date:2018/11/16
IDE:Visual Studio 2013
*/
#include<iostream>
using namespace std;
int main()
{
	int village;//村庄
	int duck = 2;//经过7个村子之后的鸭子剩余数
	int count = 0;//鸭子总数
	cout << "经过第7个村庄后,鸭子剩余" << duck << "只" << endl;
	for (village = 0; village<7; village++)//经过7个村庄
	{
		count = (duck + 1) * 2;//每经过一个村庄之前剩余的鸭子数量
		duck = count;//将值传给duck,获得最终鸭子数,实现递归
		/*剩余的鸭子数+1才是卖出之前总鸭子数的一半,例如:
		经过第7个村庄后剩余2只鸭子,那么经过第7个村庄之前的总鸭子数为:duck=(2+1)*2
		在第7个村庄卖出count/2+1只鸭子,剩余duck-((count+1)/2+1)只
		*/
		cout << "经过第" << 7 - village << "个村庄时卖出" << (count + 1) / 2 + 1 << "只,"
			<< "剩余" << duck - ((count + 1) / 2 + 1) << "只" << endl;
	}
	cout << "出发前的鸭子总数为" << count << "只" << endl;
	//返回鸭子总数
	return count;
}

运行结果:

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;先输入的数n 进行判断,若 n = 1,则输出1,STEP=1;若输入的数为偶数, 则把它除以2,STEP+=1,接着再判断n的值;若为奇数则乘3加1,STEP+=1,接着继续判断;直到n = 1时停止。

算法分析

n为输入的自然数,step为步数。

算法实现:

while (1)
	{
		if (n % 2 == 0)    //如果n是偶数
		{
			n = n / 2; //将n除以2之后将值再传给n,再接着判断是偶数还是奇数
			cout << n * 2 << "/2=" << n << endl;//输出偶数算式
			 step += 1;//记录n为偶数时循环次数
			/*递归出口,当n=1时输出需要的步数,退出递归*/
			 if (n == 1)
			 {
				 cout <<"共需要的步数(输入的自然数算第一步):STEP="<< step << endl;//输出需要的步数
				 break;
			 }
		}
		else    //如果n是奇数
		{
			n = n * 3 + 1;//将n*3+1再传给n,接着再判断是奇数还是偶数
			cout << (n - 1) / 3 << "*3+1=" << n << endl;//输出奇数算式
			 step += 1;//记录n为奇数的循环次数
		}
	}

源代码:

/*
File Name:jiaogu.cpp
Author:
Date:2018/11/16
IDE:Visual Studio 2013
问题描述:
输入一个自然数,若为偶数,则把它除以2,
若为奇数,则把它乘以3加1。
经过如此有限次运算后,总可以得到自然数值1。
求经过多少次可得到自然数1。
*/
#include<iostream>
using namespace std;
/*递归函数,传入自然数和步数*/
int JiaoGu(int n, int step)
{
	/*循环体,实现递归操作,直到自然数n=1时退出*/
	while (1)
	{
		if (n % 2 == 0)    //如果n是偶数
		{
			n = n / 2; //将n除以2之后将值再传给n,再接着判断是偶数还是奇数
			cout << n * 2 << "/2=" << n << endl;//输出偶数算式
			 step += 1;//记录n为偶数时循环次数
			/*递归出口,当n=1时输出需要的步数,退出递归*/
			 if (n == 1)
			 {
				 cout <<"共需要的步数(输入的自然数算第一步):STEP="<< step << endl;//输出需要的步数
				 break;
			 }
		}
		else    //如果n是奇数
		{
			n = n * 3 + 1;//将n*3+1再传给n,接着再判断是奇数还是偶数
			cout << (n - 1) / 3 << "*3+1=" << n << endl;//输出奇数算式
			 step += 1;//记录n为奇数的循环次数
		}
	}
	return n;//返回自然数
}
void  main()//主函数
{
	int n;//自然数
	int step=1;//计算需要的步数,从输入的数开始就算第一步 
	cout << "请输入一个自然数:" << endl;
	cin >> n;//从键盘输入一个自然数
	cout << "过程如下所示:" << endl;
	JiaoGu(n, step);//调用递归函数,传入一个自然数与初始步数
}

运行结果:

    

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

题目分析:由题目可知,数字所对应的字符串为:0—“”,1—“”,2—“ABC”,3—“DEF”,4—“GHI”,5—“JKL”,6—“MNO”,7-“PQRS”,8—“TUV”,9—“WXYZ”,与手机键盘对应。数字与字符数对应关系:0—0,1—0,2—3,3—3,4—3,5—3,6—3,7—4,8—3,9—4。

算法分析:递归出口是:当输入的是一个数字时,返回这个数字所有可能性的组合,递归体是当输入一串数字,每个数字代表不同的字符串,返回最后一个数字跟前面已产生的字符串进行组合。如输入567,则有3*3*4=36种组合,每一个组合必定包含三个字符串,如{“JMP”,“JNP”….}等。

算法实现:

if (p == len)//如果数组遍历至最后一位,退出递归

       {

              cout << output << endl;//输出所有字符串组合

       }

       for (int i = 0; i<number[input[p]]; i++)//遍历数组number

       {

              output[p] = ph[input[p]][i];//将所有可能的组合情况保存至output数组中

               Phone(p + 1, len);//继续递归

}

源代码:

/*

File Name:phone.cpp

Author:

Date:2018/11/16

IDE:Visual Studio 2013

*/

#include<iostream>

#include<stdio.h>

#include<stdlib.h>

using namespace std;

//定义保存对应字符串的指针数组

char* ph[10] = {"", "", "ABC", "DEF", "GHI",

"JKL", "MNO", "PQRS", "TUVW", "XYZ"};

int number[10] = { 0, 0, 3, 3, 3, 3, 3, 4, 3, 4 };//字符串个数数组

char input[50];//input数组保存从键盘输入的数字

char output[50];//output数组保存输出的字符串组合

/*定义递归函数,遍历数组*/

void Phone(int p, int len)     //p表示数组下标,len表示数组长度

{

    if (p == len)//如果数组遍历至最后一位,退出递归

    {

       cout << output << endl;//输出所有字符串组合

    }

    for (int i = 0; i<number[input[p]]; i++)//遍历数组number

    {

       output[p] = ph[input[p]][i];//将所有可能的组合情况保存至output数组中

        Phone(p + 1, len);//继续递归

    }

}

int main()

{

    int len=0;//定义数组长度变量,初始化为0

    cout << "请输入一个3到11位长的电话号码:" << endl;

    cin >> input;//将键盘输入保存至input数组中

    cout<<"该电话号码所对应字符的所有可能的组合是:"<<endl;

    len = strlen(input);//strlen()函数获取数组长度,并将长度值赋给len,

    int count = 1;//所有可能组合总数

    for (int i = 0; i<len; i++)//遍历input数组

    {

       input[i] -= '0';//转换为字符

//计算总数,例如:输入789,则寻找5,6,7所对应的number数组中的值,即3*4*4=48

       count *= number[input[i]];

    }

    Phone(0, len);//调用递归函数,数组从第一位开始遍历

    cout << "组合数:" << count << endl;

    return 0;

}

运行结果:

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

题目分析:由题可知,分完之后6兄弟手中的橘子一样多,即每个人手中的句子为avg=2520/6=420;因为老六分出1/3给老大之后手中剩余420个橘子,所以老六之前总的橘子数为:420/(3/2)=630个,所以他分给老大的橘子数为630*(1/3)=210个,设老大原来手中剩余的橘子数为x,那么分完之后他的橘子数为x+210=420个,所以他手中原来有x=210只。由于他需要分给老二1/8,所以210只是他分完之后剩余的,所以他原来拥有的橘子数为210*(8/7)=240只橘子。以此类推即可算出其他人原来手中有的橘子数。

算法分析:

f(x)为原来手中的橘子数,divide为分出去的橘子数,i表示儿子,从1-6。6个儿子。递归出口为i=7。即只计算到第6个儿子,到第7个时结束。

算法实现:i

f (i == 0)//如果是第一个儿子

      {

             num = avg / 2 * (8 - i) / (8 - i - 1);

             divide = num / (8-i);

             return cal(i + 1);//返回cal函数下一个儿子的橘子数计算方法

      }

      else  if (i > 0 && i < 6)  //从第二个儿子开始

      {

             num = avg*(8 - i) / (8 - i - 1) - divide;//原本拥有的橘子数=总数-前一个儿子分给他的数量

             /*从第二个儿子开始每次分给下一个人的橘子数divide=原本橘子数+上一个儿子分过来的橘子数*/

             divide = (num+divide) / (8 - i );

             return cal(i + 1);//递归

      }

      else

             //如果i=6,即超过6个数,则退出递归

             return;

源代码:

/*
File Name:Orange.cpp
Author:
Date:2018/11/16
IDE:Visual Studio 2013
*/

#include<iostream>

using namespace std;

int num;//表示每个人原来手里的橘子数

int avg = 420;//分完的结果为等值240

int divide;//分出去的橘子数,即下一个儿子得到的橘子数

/*递归函数,计算原本橘子数和分出的橘子数,返回下一个儿子,当i=6时退出递归*/

void cal(int i)

{

    if (i == 0)//如果是第一个儿子

    {

       num = avg / 2 * (8 - i) / (8 - i - 1);

       divide = num / (8-i);

       cout << "老" << i + 1 << "原本拥有的橘子数:" << num << "个,"

           << "分出去的橘子数:(即下一个儿子得到的橘子数)" << divide << "个" << endl;

       return cal(i + 1);//返回cal函数下一个儿子的橘子数计算方法

    }

    else  if (i > 0 && i < 6)  //从第二个儿子开始

    {

       num = avg*(8 - i) / (8 - i - 1) - divide;//原本拥有的橘子数=总数-前一个儿子分给他的数量

       /*从第二个儿子开始每次分给下一个人的橘子数divide=原本橘子数+上一个儿子分过来的橘子数*/

       divide = (num+divide) / (8 - i);

       cout << "老" << i + 1 << "原本拥有的橘子数:" << num << "个,"

           << "分出去的橘子数:(即下一个儿子得到的橘子数)" << divide << "个" << endl;

       return cal(i + 1);//递归

    }

    else

       //如果i=6,即超过6个数,则退出递归

       return;

}

/*主函数*/

int main (){

    cal(0);//调用递归函数,从第一个儿子开始

}

运行结果:

  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是C++生成二叉树实现遍历的完整代码,先序遍历采用算法,层次遍历采用非算法,并附带一个例子: ```c++ #include <iostream> #include <queue> using namespace std; struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; // 生成二叉树 void createTree(TreeNode*& root) { int val; cin >> val; if (val == -1) { root = NULL; return; } root = new TreeNode(val); createTree(root->left); createTree(root->right); } // 先序遍历(归) void preorderTraversal(TreeNode* root) { if (root == NULL) { return; } cout << root->val << " "; preorderTraversal(root->left); preorderTraversal(root->right); } // 层次遍历(非归) void levelOrderTraversal(TreeNode* root) { if (root == NULL) { return; } queue<TreeNode*> q; q.push(root); while (!q.empty()) { TreeNode* node = q.front(); q.pop(); cout << node->val << " "; if (node->left) { q.push(node->left); } if (node->right) { q.push(node->right); } } } int main() { TreeNode* root; cout << "请输入二叉树节点的值,-1表示该节点为空:" << endl; createTree(root); cout << "先序遍历结果:"; preorderTraversal(root); cout << endl; cout << "层次遍历结果:"; levelOrderTraversal(root); cout << endl; return 0; } ``` 例子: 输入: ``` 请输入二叉树节点的值,-1表示该节点为空: 1 2 4 -1 -1 5 -1 -1 3 -1 6 7 -1 -1 -1 ``` 输出: ``` 先序遍历结果:1 2 4 5 3 6 7 层次遍历结果:1 2 3 4 5 6 7 ``` 希望能够帮到你!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值