第二章递归与分治策略的学习流程如下:
分析问题、寻找递归关系:找出大规模问题与小规模问题的关系,这样通过递归使问题的规模逐渐变小。
设置边界、控制递归:找出停止条件,即算法可解的最小规模问题。
设计函数、确定参数:和其他算法一样设计函数体中的操作及相关参数。
2.1.1求阶乘
代码:
#include <iostream>
#include <cstring>
using namespace std;
int fun(int n)
{
if(n==0) return 1;
else return n*fun(n-1);
}
int main()
{
int n;
cin>>n;
cout<<fun(n);
}
2.1.2二叉树叶子节点数
输入:ABD@F@@@CE@@@
代码:
#include <iostream>
#include <cstring>
using namespace std;
typedef struct tree
{
char data;
struct tree *lchild,*rchild;
}*NodeTree,BiTree;
NodeTree CreateTree()
{//递归中序建树
NodeTree t;
char c;
scanf("%c",&c);
if(c=='@')
t=NULL;
else
{
t=(NodeTree )malloc(sizeof(BiTree));
t->data=c;
t->lchild=CreateTree();
t->rchild=CreateTree();
}
return t;
}
int CountLeaves(BiTree *t)
{
if(t==NULL)//0片叶子
return 0;
else if(t->lchild==NULL&&t->rchild==NULL)
//叶节点无左右儿子
return 1;
else//度数>0的结点进入递归,找到叶节点则累加
return CountLeaves(t->lchild)+CountLeaves(t->rchild);
}
int main()
{
NodeTree t;
t=CreateTree();
cout<<CountLeaves(t);
return 0;
}
2.1.3Hanio塔
参考链接
(1)移动规则:
1.每次只能从一个柱子的最上面移动一个碟子到另外一个柱子上。
2.不能将大碟子放到小碟子的上面。
(2)分析问题:
假设A上面有N个盘子,如果我呢把N-1个盘子已经搬到了B上面,我只需要将A盘子放到这个C上面,第N个盘子的直径是最大的,再以后的搬动过程中是不需要动C上第N个盘子的。以上搬动N个盘子的问题,就变为搬N-1个盘子的问题。如此规则执行下去,只后只有一个圆盘的时候,问题直接解决了。
这种方式适合递归算法
1 有递归出口,那就是当盘子只有一个时候,问题很简单,直接解决
2 有策略能使问题规模缩小,并且问题是相似,
a 将N-1个盘子从A 搬到B柱上面,(借助C)
b 将A柱子上第N个盘子搬到C柱上面
c 将B柱子上N-1个盘子搬到C柱子上面 (借助A)
#include <iostream>
#include <cstring>
using namespace std;
void Hanio(int n,int a,int b,int c)
{
if(n==1)
{
printf("将第%d个盘子从%c移到%c上\n",n,a,c);
}
else
{
Hanio(n-1,a,c,b);//将前n-1个盘子从a借助c移到b
printf("将第%d个盘子从%c移到%c上\n",n,a,c);
Hanio(n-1,b,a,c);//将前n-1个从b借助a移到c
}
}
int main()
{
int n;
printf("请输入要移动的块数:");
cin>>n;
Hanio(n,'A','B','C');
return 0;
}
//3
输出:
2.1.4全排列
设 R = { r 1 , r 2 , … , r n } R=\{{r_1,r_2,…,r_n}\} R={r1,r2,…,rn}是要进行排列的n个元素,求R的全排列 P e r m ( R ) Perm(R) Perm(R)。注:perm是permutation(排列的缩写)
例:{1,2,3}的全排列
从分治的角度考虑,可以划分为多个子问题,"1开头的全排列","2开头的全排列"...
当问题划分到单独数字的全排时无需划分,递归结束。
代码解释:
#include <iostream>
#include <cstring>
using namespace std;
void Swap(int &x,int &y)
{
//交换a数组中的a[x]、a[y]
int tmp = x;
x = y;
y = tmp;
}
void Perm(int a[],int k,int m)
{
//k表示当前数字,m表示数字总数
int i;
if(k==m)//递归到最后一个数字输出
{
for(i=0; i<=m; i++)
cout<<a[i]<<' ';
cout<<endl;
}
else
{
for(i=k; i<=m; i++)
{
Swap(a[i],a[k]);//先和当前换
Perm(a,k+1,m);//换完对下一个递归交换
Swap(a[i],a[k]);
}
}
}
int main()
{
int n,a[100];
cin>>n;
for(int i=0; i<n; i++)
{
cin>>a[i];
}
Perm(a,0,n-1);
return 0;
}
//3
输出:
2.1.5瑞格习题:递归求最大值
#include <iostream>
#include <cstring>
using namespace std;
int getMax(int a[],int l,int r)
{
int mid = (l+r)/2;
int lmax,rmax;
if(l==r) return a[l];
else
{
lmax = getMax(a,l,mid);//对左边其最大
rmax = getMax(a,mid+1,r);//对右边其最大
return lmax>rmax?lmax:rmax;//取左右最大的
}
}
int main()
{
int n, a[100];
cin>>n;
for(int i= 0; i<n; i++)
{
cin>>a[i];
}
cout<<getMax(a,0,n-1);
}