您的位置:首页 > 编程语言 > C#

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

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

先看看题目吧:

二叉树

发布公司:
有 效 期:
赛 区:

---

2014-02-19至2014-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
=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,提交,通过。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: