给定n个节点,一共有多少个二叉树形态
设计一个递归算法,求在给定二叉树的结点总数N的情况下,二叉树可能拥有的形状数M。
例如
满足要求的任何一棵二叉树都是高度为N的满二叉树从根结点开始的子树。将这棵满二叉树的结点按照从上至下、从左至右的顺序进行编号,根结点的编号为1,则可以按层次输出任何结点总数为N的二叉树的所有结点编号。例如当N=3时,输出结果为:
1: 1, 2, 3
2: 1, 2, 4
3: 1, 2, 5
4: 1, 3, 6
5: 1, 3, 7
tree_count is 5 when N is 3
解答采用c++语法,运用了主要c语法以及&符号
递归实现版本
#include<stdio.h>
#include<math.h>
void arrange(int arr[],int idx,int N,int &tree_count,double &height)
{
int i=0;
int flag=-1;
if(idx==0)//idx为0时特殊实现
{
arr[idx]=1;
arrange(arr,idx+1,N,tree_count,height);
}
if(idx==N)//idx为N时则打印
{
tree_count++;
printf("%d:",tree_count);
for(int k=0;k<N;k++)
{
printf("%d ",arr[k]);
}
int h=(int)log2(arr[N-1]);
printf("%20dheight",h);
height+=h;
printf("\n");
}
if(idx>0&&idx<N)
{
for(i=arr[idx-1]+1;i<=arr[idx-1]*2+1;i++)//利用顺序的排列,idx上的值要大于idx-1上的值
{
flag=-1;//设置标志位为-1假如为1就进入下一个位置上值的寻找
arr[idx]=i;
int k=0;
for(;k<idx;k++)//查看当前的arr[idx]是否合法
{
if((arr[idx]==arr[k]*2)||(arr[idx]==arr[k]*2+1))
{
flag=1;
break;//如果合法就break进入下一个位置寻找,由于栈会保留前面所有值
}
}
if(flag==1)
{
arrange(arr,idx+1,N,tree_count,height);//寻找下一个位置上的值
}
}
}
}
int main()
{
int arr[5];
int tree_count=0;
int idx=0;
int n=6;
double height=0;
arrange(arr,idx,n,tree_count,height);
printf("tree_count is %d when N is %d\n",tree_count,n,height);
printf("average height=%f",(double)height/(double)tree_count);//求平均高度
printf("\n log2N=%f",log2(n));//运用math函数
int c=1,i=0;//卡塔兰数的实现
for(i=n+2;i<=2*n;i++) //2n!/((n!)*n+1)-->2n!/(n+1)!
c*=i;
for(i=1;i<=n;i++) //2n!/((n!)*(n+1)!)
c/=i;
if(c==tree_count)
printf("\nM和N之间满足卡塔兰数关系\n");
else
printf("M和N之间不满足卡塔兰数关系\n");
}
递推实现版本
#include<stdio.h>
void buildtree(int N,int &tree_count)
{
tree_count=0;
int arr[N]={0};
int arrappend[N]={0};
int idx=0;
arr[0]=1;
int tag=-1;
int l=0;
while(idx>-1)
{
while(arrappend[idx]<idx&&arr[arrappend[idx]]*2+1<=arr[idx]&&idx!=N-1)
{
arrappend[idx]++;
}
//找到arrappend的值
if(idx<N-1)
{
if(tag==1)
{
arrappend[idx]=0;
idx--;
tag=-1;
while(arr[idx]*2+1==arr[idx+1])
{
idx--;
arrappend[idx+1]=0;//如果退后那么把后面arrappend的值抹去
}
continue;
}
else
{
if(arr[arrappend[idx]]*2==arr[idx])//如果2倍那么设为2倍加一
{
arr[idx+1]=arr[arrappend[idx]]*2+1;
idx++;
arrappend[idx-1]++;
continue;
}
if(arr[arrappend[idx]]*2>arr[idx]&&arr[arrappend[idx]]*2!=arr[idx+1])
{
//如果新的值不为2倍就设置为2倍
arr[idx+1]=2*arr[arrappend[idx]];
idx++;
continue;
}
if(arr[arrappend[idx]]*2==arr[idx+1])//与arr[idx+1]比较与上面不同
{
arr[idx+1]=arr[arrappend[idx]]*2+1;
idx++ ;
arrappend[idx-1]++;
continue;
}
if(arr[arrappend[idx]]*2<arr[idx+1])//如果当前的arrappend不行就加一
{
arrappend[idx]++;
}
}
}
else
{
tree_count++;
printf("%d:",tree_count);
for(int k=0;k<N;k++)
{
printf("%d ",arr[k]);//打印出一条路径
}
for(int k=0;k<N;k++)
{
printf(" %d ",arrappend[k]);
}
printf("\n");
if(arr[idx]==arr[idx-1]*2+1)
{
tag=1;
arr[idx]=0;
}
idx--;
}
}
}
int main()
{
int N=9;
int tree_count=0;
buildtree(N,tree_count);
printf("\n%d 个",tree_count);
}
以上两种方式还留有优化空间