【问题标题】:Get the index of a node's parent, passing its index, in a balanced tree在平衡树中获取节点父节点的索引,传递其索引
【发布时间】:2014-05-20 00:57:19
【问题描述】:

示例:

我有以下示例,说明冠军赛时间表:

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...}

问题:

我需要找到一个数学函数,它会返回节点父节点的值,并传递它的值。而且这个数学函数必须可以用 C# 来表示。

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

功能应该如何?

【问题讨论】:

  • GetNodeParent(Int32 nodeIndex) 方法没有足够的信息来完成任务。除了节点数之外,它还需要知道节点总数或级别数(实际上是等价的)。
  • 你传递的是索引还是值?因为如果你只传递值,你也需要传递整个数组。如果您正在传递值(根据您的示例,我认为您是这样),那么您在那里所做的命名非常糟糕。
  • 我需要通过索引。我的索引不是从0开始的,根是最后一个索引。
  • 哦,我明白了,那是因为你的树是自上而下的。通常你从索引 0 的根目录开始,我的错。
  • 用最小公倍数计算树中有多少层!

标签: c# math logic nodes treenode


【解决方案1】:

在我看来,处理此问题的最简单方法是将您的树以相反的方式存储。通常,平衡树可以在一个数组中表示,其中根位于第一个位置,叶子位于最后一个 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);

这可以通过根据您的示例值的位置进行的简单单元测试来验证:

[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,因为这是它们在树中的索引,根在第一个位置,其构造类似。您提供的示例将是这样构造的:

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 值。我认为我在问题上使用的索引一词令人困惑,因为它不是数组或列表或 w/e 的索引。这只是价值。我没有真正的树结构,其中节点引用其父级。这棵树只是我的冠军赛程的一个例证。
  • 嗯,那么最简单的处理方法就是将第一场比赛视为决赛。但是,由于所有游戏都是不同的,您可以使用最后描述的“IndexOf”部分来获取真正的数组索引。但是每次进行心理转换可能会很麻烦。我还详细介绍了一种按层获取游戏的方法,如果这能有所帮助的话……
【解决方案2】:

选项 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?,然后在方法中进行检查,这样它就会返回null

【讨论】:

  • 遗憾的是,我无法在现实世界的情况下构建新的反向树。
【解决方案3】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-13
    • 1970-01-01
    • 2011-08-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    相关资源
    最近更新 更多