poj 1095 二叉树的编号

该博客介绍了一个关于二叉树编号的问题,即给定一个序号n,如何根据数学模型和递归算法打印出对应的二叉树结构。作者首先解释了二叉树编号的规则,然后通过计算f(m)数组来确定树的节点数量,并使用递归方法m_tree_print()分别打印左子树和右子树。最后提供了一个主函数nth_tree_print()用于输入序号并输出二叉树结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


/*
 *  poj 1095 二叉树编号

    题目大意:
    
        二叉树按照如下规则进行编号:

            1、0个节点的空树编号为0
            
            2、单个节点的树编号为1

            3、任意包含m个节点的二叉树,其编号必然小于任意一个包含m+1个节点的二叉树

            4、包含相同节点的二叉树,左子树如果相同,大小取决于右子树的大小比较,如果
               左子树不同,则大的编号较大。公式如下:

                               |-- n(L(T1)) > n(L(T2))
               n(T1) > n(T2) --|
                               |-- n(L(T1))= n(L(T2)) && n(R(T1)) > n(R(T2))

            求给定序号的二叉树打印.

        数学模型:
            令f(m)表示包含m个节点的二叉树的个数,则有如下公式成立:

                f(m) = sum{f(k)*f(m-1-k) | k->0~m-1}

        解题思路:
            本题与poj 1019数列问题有点象,同样是打印出序号为n的元素。解法也类似

            1、根据上面求出的f(m)数组,可以判断出给定的序号为n的二叉树包含的节点个数

            2、然后枚举右子树的元素个数(从m-1到0),找出左右子树的元素个数

            3、
            
*/
#include <stdio.h>

#define M_MAX 18

unsigned int f[M_MAX+1];

/*
    打印包含m个节点的,内部编号为num的二叉树。递归实现
*/
void m_tree_print(int m, unsigned int num)
{
    int l, r, l_th, r_th;

    if(m==1) {printf("X");return ;}
    if(m==2) 
    {
        if(num==1) printf("X(X)");
        else printf("(X)X");
        return ;
    }


    // 计算右子树包含节点数
    for (r=m-1; r>=0; r--)
    {
        if (num <= f[r]*f[m-1-r]) break;

        num -= f[r]*f[m-1-r];
    }

    // 计算右子树包含节点数
    l = m-1-r;

    // 计算左子树内部编号 -- 从1开始
    for (l_th=1; true; l_th++)
    {
        if (num <= f[r]) break;

        num -= f[r];
    }

    // 右子树内部编号 -- 从1开始
    r_th = num;

    // 打印左子树
    if (l!=0)
    {
        printf("(");
        m_tree_print(l, l_th);
        printf(")");
    }

    // 打印根节点
    printf("X");

    // 打印右子树
    if (r!=0)
    {
        printf("(");
        m_tree_print(r, r_th);
        printf(")");
    }
}

/*
    打印外部编号为nth的二叉树
*/
void nth_tree_print(unsigned int nth)
{
    int m=1, m_nth=nth;

    // 计算二叉树包含的节点数m
    for (; m<=M_MAX; m++)
    {
        if (m_nth <= f[m]) break;

        m_nth -= f[m];
    }

    m_tree_print(m, m_nth);
}

int main()
{
    unsigned int nth;

    // 打表,计算各m个节点二叉树所占个数
    f[0]=1;
    for (int m=1; m<=M_MAX; m++)
    {
        for (int k=0; k<m; k++)
        {
            f[m] += f[k]*f[m-1-k];
        }
    }

    scanf("%d", &nth);
    while (nth!=0)
    {
        nth_tree_print(nth);
        printf("\n");

        scanf("%d", &nth);
    }
    
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值