获取节点父节点的索引,并在平衡树中传递其索引

时间:2014-05-20 00:57:19

标签: c# math logic nodes treenode

实施例

我有以下示例,说明了锦标赛时间表:

1 2  3 4  5 6  7 8
 |    |    |    |
 9   10    11  12
   |         |    
  13         14 
        |
       15

规则:

数字代表节点的值(匹配)。值从顶部开始到根,因为根是冠军的最终匹配。

树将始终平衡,并且可以有N个顶部位置,其中N = {2,4,8,16,32,64,128,256 ...} < / p>

问题:

我需要找到一个数学函数,它将返回节点parent的值,并传递其值。此数学函数必须可以用C#表示。

GetNodeParent(9); // must return 13
GetNodeParent(10); // must return 13
GetNodeParent(4); // must return 10
GetNodeParent(15); // must return null

该功能应该如何?

3 个答案:

答案 0 :(得分:2)

在我看来,处理这个问题的最简单方法是以相反的方式存储树。通常情况下,平衡树可以在数组中表示,其中根位于第一个位置,而叶子位于最后n/2个位置,如下所示:

         1
         |
   2            3 
   |            |  
 4   5       6      7  
 |    |      |      |
8 9 10 11  12 13 14 15

在内存中看起来像这样:

1|2|3|4|5|6|7|8|9|10|11|12|13|14|15

现在这个结构的一个有趣的属性是父母总是 Math.Floor(index/2)(所以孩子们在n*2n*2+1

例如,13的父级是13/2 = 6.5 =floored= 6。它确实简化了操作。

如前所述,所有叶节点都在最后的n / 2个位置。这是另一个有趣的特征;如果你正在寻找第一轮比赛,只需砍下你的阵列并拿走Math.Ceiling(n/2)最后一项:

1 | 2 | 3 | 4 | 5 | 6 | 7 |的 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15

对于第二轮,移除上一轮并再次在Math.Ceiling(n/2)

进行切割

1 | 2 | 3 |的 4 | 5 | 6 | 7 |


知道这一点,GetParent可能如下所示:

public static int? GetParent(int childIndex)
{
    int parentIndex = (int) Math.Floor((double)childIndex/2);
    return parentIndex == 0 ? (int?)null : parentIndex;
}

或直接return (int)Math.Floor((double)index/2);如果您不需要空值。

这可以通过这个简单的单元测试来验证,该单元测试来自您的示例值&#39;位置:

[TestMethod]
public void TestMethod1()
{
    Assert.AreEqual(2, Stuff.GetParent(4));
    Assert.AreEqual(2, Stuff.GetParent(5));
    Assert.AreEqual(6, Stuff.GetParent(13));
    Assert.AreEqual(null, Stuff.GetParent(1));
}

并且不要忘记使用索引而不是值,你不能直接应用9并从你的例子中得到13,现在它是4和2因为那个&#39;它们在树中的索引,根位于第一个位置,构造如下。您提供的示例将构造如下:

15|13|14|9|10|11|12|1|2|3|4|5|6|7|8

如果您需要按值工作,可以使用IndexOf。由于您基于1而不是基于0,因此您还需要为每个索引添加1。这看起来像这样:

    [TestMethod]
    public void TestMethod1()
    {
        List<int> values = new List<int>{15, 13, 14, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8};

        Assert.AreEqual(values.IndexOf(13) + 1, Stuff.GetParent(values.IndexOf(9) + 1));
        Assert.AreEqual(values.IndexOf(13) + 1, Stuff.GetParent(values.IndexOf(10) + 1));
        Assert.AreEqual(values.IndexOf(10) + 1, Stuff.GetParent(values.IndexOf(4) + 1));
        Assert.AreEqual(null, Stuff.GetParent(values.IndexOf(15)));
    }

答案 1 :(得分:0)

选项1:构建一个相反的新树,以便您可以使用二叉树。


选项2:

致电list_name.Count(),我已为您的案件使用了15

GetNodeParent(9,15); // return 13
GetNodeParent(10,15);// return 13
GetNodeParent(4,15); // return 10

这样可行,但您必须检查最终案例(在您的情况下为15):

int GetNodeParent(int aNodeValue, int aListSize) {
    aNodeValue.Dump("Look for the parent of");
    var depth = (int)(Math.Log(aListSize,2) ); // this rounds down
    var level = Math.Pow(2,depth);
    while (aNodeValue > level) {
        depth--;
        level += Math.Pow(2,depth);
    }
    var target = level+1;   // this will be our accumulator
    var search = level;     // for our "binary search"
    var search_width = Math.Pow(2,depth).Dump("width");
    // This runs a "binary search", adding 1 to our result
    // if we are on the right side.
    while (search_width!=0){
       if (aNodeValue > level)
            target++;
        search -= search_width / 2;
        search_width /=2;
    }       

    return (int)target;
}

作为后来的想法,在调用方法之前为if (aNodeValue == list_name.Count())添加null,或者将签名更改为int?并在方法中进行检查以便&#39 ; ll返回null

答案 2 :(得分:0)

你试过这个简单的公式吗?

GetNodeParent(k) = (k + 1) div 2 + N
(if >=2N then null)

其中 div 是整数除法(7 div 2 = 3)