题目要求:略
思路:首先,设拥有N个结点的不同形态的有序二叉树有L[N]棵。L[N]即为卡特兰数。那么:
(1).针对这个问题先转换为输入N,求n和k。n表示编号为N的树所拥有的结点数。k表示这棵编号为N的树是拥有结点数为n的树的有序集合的第几棵。我们可以先将Catalan数表打出来:
int L[19]=
{1,1,2,5,14,42,132,429,1430,4862,16796,58786,208012,742900,2674440,9694845,35357670,129644790,477638700};
对于输入的N,可以求出n=min(j|L[0]+L[1]+...+L[j]>=N)。而k=n-L[0]-L[1]- ...-L[n-1]。
鉴于二叉树的固有特性,我可以构造递归函数fun(n,k)。即打印出拥有n个结点树的第k种状态。
(2).继续转化问题,这棵树的左子树和右子树各有结点数多少?设这棵树左子树的结点数为i,右子树的结点数为n-i-1,那么这棵树是又左子树的结点数为i,右子树的结点数为n-i-1的形态的第几种(设为第s种)?可以知道当1<=k<=L[0]*L[n-1]时,左子树结点树为0,右子树结点数为n-1,s=k;L[0]*L[n-1]+1<=k<=L[1]*L[n-2]时,,左子树结点树为1,右子树结点数为n-2,s=k- L[0]*L[n-1] ;...当L[i-1]*L[n-i]+1<= L[i]*L[n-i+1]时,左子树结点树为i,右子树结点数为n-i-1,s= k- L[0]*L[n-1]- ... L[i-1]*L[n-i]。
(3).继续想象s增长的过程即为树形态不断发生变化的过程。那么首先是右子树在发生变化,从1到L[n-i-1]。继续增长,右子树的形态复位为1,而左子树的形态增加1.因此右子树相当于秒针,左子树相当于分针。对于s,该树的左子树编号为(s-1)/L[n-i-1]+1,右子树编号为(s-1)% L[n-i-1]+1。
(4).fun(n,k)的递归终止条件很容易知道,为n==1。此时树的形态只有一种,所以直接打印X。
(5).综上所述,fun(n,k)的形式为:
fun(n,k){
if(1==n)打印X,返回。
求出 s,i;
If(i>0){打印(;fun(i, (s-1)/L[n-i-1]+1);打印);}
打印X;
If(n-i-1>0) {打印(;fun(n-i-1, (s-1)%L[n-i-1]+1);打印);}
}
至此,问题得到了解决。代码如下: