二叉树-c#求解-英雄会在线编程题目

         二叉树的题,呵呵,说句实话,不喜欢做这种题,为什么,题目看着都感觉好抽象啊,不过好奇总是害死猫。

先看看题目吧:

二叉树
  • 发布公司:
  • 有 效 期:
  • 赛    区:
  • ---                
  • 2014-02-192014-03-21
  • 北京
  • 难 度 等 级:
  • 答 题 时 长:
  • 编程语言要求:
  • 120分钟
  • C C++ Java C#                 
题目详情

我们可以用如下如下方法给二叉树编号:

(1) 空树编号为0

(2) 只有一个结点的树编号为1

(3) 对任意非负整数m,包含有m个结点的二叉树编号笔包含有(m + 1)个结点的二叉树编号小

(4) 对一个包含有m个结点的二叉树,假设它左子树编号是L,右子树编号是R,它的编号是n,当且仅当,所有编号大于n并且包含m个结点的二叉树,满足以下如下条件:

(a) 其左子树编号大于L

或者

(b) 其左子树编号等于L,并且右子树编号> R

下图是编号为0-9的二叉树,以及编号为20的二叉树。



现给定编号n(1<=n <=500000000),求编号为n的二叉树。

二叉树的左孩子和右孩子递归表示。

即 单个结点用X表示,

如果二叉树只有左孩子L,则要表示成(L)X

如果二叉树只有右孩子R,则要表示成X(R)

否则,左右子树都要表示,即表示成(L)X(R)。

例如编号为20的树表示成:

((X)X(X))X

    

题目的意思就是给定序号的二叉树,用个字符串表示出来。

现在来分析下这个二叉树的排序规律。二叉树跟节点数相关,所以,我们就吧这些二叉树首先按照这点个数分类。

节点个数为0,只有一种情况,记做tree[0]=1;

节点个数为1,也只有一种,记做tree[1]=1;

分析下来很容易得到:

节点个数为n的二叉树的个数:tree[n]=tree[0]*tree[n-1]+tree[1]*tree[n-2]+.....+tree[n-1]*tree[0]

       那么对于给定的序号n,就表示有n+1个树。(因为是从0开始编号的嘛),由上面的公式,我们很容易用递归调用得到编号为n的树,左树有多少个节点leftnode,右树有多少个节点rightnode

     下一步是是要知道,左树在这leftnode个节点中,是第几个,右树在这rightnode个节点中,是第几个。这个可以从序号规律得到。

函数:m表示当前树有多少个节点,x表示还剩下多少个(即已经减去0~m-1节点出现的可能情况。nodes就是前面的树数组。

static string  cal(int m, int x,int[] nodes)
        {
            string result = "";
            int count = 0;
            int nodessum = 0;
            bool flag = false;
            for (int i = 0; i < m; i++)
            {
                nodessum = nodes[i] * nodes[m - 1 - i];
                count += nodessum;
                if (x > nodessum)
                {
                    x -= nodessum;
                }
                else
                {
                    double d = (double)x / (double)nodes[m - 1 - i];

                     //这里就是求左树有i个节点时,第多少个
                    int leftindex = (int)Math.Ceiling(d);

                    //右树第多少个
                    int rightindex = x % nodes[m - 1 - i];
                    if (rightindex == 0)
                    {
                        rightindex =  nodes[m - 1 - i];
                    }

                    //print函数就是把有m个节点,第x个的树用字符串表示出来
                    string leftstr = print(i, leftindex, nodes);
                    string rightstr = print(m - 1 - i, rightindex, nodes);
                    if (leftstr == "")
                    {
                        result = "X";
                    }
                    else
                    {
                        result = "(" + leftstr + ")X";
                    }
                    if (rightstr == "")
                    {
                    }
                    else
                    {
                        result = result + "(" + rightstr + ")";
                    }
                    flag = true;
                    break;
                }
            }
            if (!flag)
            {
                nodes[m] = count;
                result = cal(m + 1, x, nodes);
            }
            return result;
        }

现在来看print函数:

static string print(int m, int index, int[] nodes)
        {
            string result = "";
            if (m == 1)
            {
                return "X";
            }
            if (m == 0)
            {
                return "";
            }
            int nodessum = 0;
            for (int i = 0; i < m; i++)
            {
                nodessum = nodes[i] * nodes[m - 1 - i];
               
                if (index > nodessum)
                {
                    index -= nodessum;
                }
                else
                {
                    double d = (double)index / (double)nodes[m - 1 - i];
                    int leftindex = (int)Math.Ceiling(d);
                    //int leftindex = (int)Math.Ceiling((double)(index / nodes[m - 1 - i]));
                    int rightindex = index % nodes[m - 1 - i];
                    if (rightindex == 0)
                    {
                        rightindex = nodes[m - 1 - i];
                    }
                    string leftstr = print(i, leftindex, nodes);
                    string rightstr = print(m - 1 -i, rightindex, nodes);
                    if (leftstr == "")
                    {
                        result = "X";
                    }
                    else
                    {
                        result = "(" + leftstr + ")X";
                    }
                    if (rightstr == "")
                    {
                    }
                    else
                    {
                        result = result + "(" + rightstr + ")";
                    }
                    break;
                }
            }
            return result ;
        }

可以看到print函数和cal函数有很大一部分是完全相同的,一个是从前向后找到第多少个节点,一个是知道了多少个节点,和序号,向前递推,输出字符串。感觉应该可以综合下。

    最后就是在main函数里面调用,初始化nodes数组

int[] nodes = new int[1000];
            nodes[0] = 1;
            nodes[1] = 1;
            string result = "";
            if (x == 1)
            {
                result = "X";
            }
            else
            {
                result = cal(2, x-1 , nodes);
            }
            return  result;

其实nodes数组可以初始化小点,从前面分析可以看出,节点数增加时,其个数增加非常快,基本上序号达到500000000时,节点估计也在100以内,好像才18吧。

 

ok,提交,通过。

没有更多推荐了,返回首页