【问题标题】:Populating a binary tree填充二叉树
【发布时间】:2020-09-22 08:14:06
【问题描述】:

我无法理解我的函数中缺少的东西来填充二叉树与手动输入。 打印头部值及其左右节点值似乎对我也没有帮助,因为它看起来对我来说是正确的。但是,在自动填充后打印出所有值会产生奇怪的结果。

这个二叉树的值将来自一个数组:

std::vector<ValueType> values = {
       3,
      7,4,
     2,4,6,
    8,5,9,3
};

这是树关系:

         3
       (7,4)
     7        4
   (2,4)    (4,6)
  2       4       6
(8,5)   (5,9)   (9,3)

如您所见,父节点位于上方,其子节点位于下方,用括号括起来。

row1: the root node 3 have left:7, right:4
row2: parent 7 have left:2, right:4
row2: parent 4 have left:4, right:6
...

这似乎不是 cmets 中提到的二叉树,而是将其视为具有空左或右节点的树或具有来自其兄弟(同一行)的共享子节点的树。

下面是自动填充二叉树的函数:

// ValueType is defined as an alias of int
void populateTree(BinaryTree* node, int rowCount, int lastIndex, std::vector<ValueType> values) {
    for (int i = 0; i < rowCount; ++i) {
        iterCount++;
        int currentRow = (i * (i + 1)) / 2;
        int x = i + 1;
        int nextRow = (x * (x + 1)) / 2;
        bool toggle = false;
        for (int j = nextRow; j < nextRow + x; ++j) {
            auto value = values[currentRow++];
            node->value = node->parent != nullptr ? value : node->value;

            if (j >= values.size())
                continue;

            auto leftValue = values[j + 0];
            auto rightValue = values[j + 1];
            node->left = new BinaryTree(node, leftValue);
            node->right = new BinaryTree(node, rightValue);

            if (j != currentRow)
                std::cout << ", ";

            std::cout << node->value << "(" << node->left->value << "," << node->right->value << ")";

            node = toggle ? node->right : node->left;
            toggle = !toggle;
        }
        
        std::cout << std::endl;
    }
}

我已使用triangular number formula 将数组映射为行和列。

现在,要确认代码是否正常工作,从下面三角形的顶部开始,移动到下一行的相邻数字,从上到下的最大总数应为 23。

我通过自底向上遍历并添加所有相邻节点组合来完成此操作。这是结果的输出:

3(7,4)
7(2,4), 4(4,6)
2(8,5), 4(5,9), 6(9,3)

iter count: 14
============
[4, 4, 7, 3]:18
[5, 4, 2, 4, 7, 3]:25
[3, 6, 4, 2, 4, 7, 3]:29
[3, 6, 4, 2, 4, 7, 3]:29
[5, 2, 4, 7, 3]:21
[4, 7, 3]:14
[4, 3]:7
pair total sum: 54

应该有[n1, n2, n3, ...nX]:23的组合。

但是,如果我手动构建二叉树,则有正确的组合:

3(7,4)
7(2,4), 4(4,6)
2(8,5), 4(5,9), 6(9,3)

iter count: 14
============
[8, 2, 7, 3]:20
[5, 2, 7, 3]:17
[5, 4, 7, 3]:19
[9, 4, 7, 3]:23 <--- this is the correct combination.
[5, 4, 4, 3]:16
[9, 4, 4, 3]:20
[9, 6, 4, 3]:22
[3, 6, 4, 3]:16
pair total sum: 83

完整源代码链接:https://gist.github.com/mr5z/8249a9101e5bfdce4850602c3ea7ebf3

这是我对project euler#18的解决方案的一部分

【问题讨论】:

  • 请在问题中包含minimal reproducible example
  • 您是否尝试过使用调试器逐句执行代码语句,同时监视变量及其值,以查看何时何地没有按预期发生?
  • @idclev463035818 我已将源代码链接减少到 151 行。够了吗?
  • @Someprogrammerdude 是的。我总是使用调试器。我很难掌握我在代码中遗漏了什么,而不是我错过了希望在调试器中看到的值。
  • 为事物使用适当的名称,以便与他人正常交流(并了解来源,无论是印刷的还是在网络上发布的)。具有“共享子节点”的节点使整个结构不是树。这是DAG 的情况,但不是树。 Tree 要求每个节点最多被引用一次,即只能是一个父节点的子节点(根节点除外,它没有父节点)。

标签: c++ binary-tree


【解决方案1】:

我不太确定为什么要实现自己的树结构,但如果您的目标是可视化某个树结构:我建议您结合使用 boost cpp graph librarygraphiz 请参阅example here,它以更“面向图形”的方式显示了家谱的构建。每个图(如树)都有节点和边。

如果您想训练您的编程技能,请继续:我发现以下b-tree 的示例在我过去非常有用。 你不能使用“普通”的 insertIntoTree 函数来代替 populateTree 函数吗?或者这对你来说是性能问题?

【讨论】:

    【解决方案2】:

    您在此处所做的是 XY 问题的示例(请参见此处:Meta StackExchange: What is the XY problem? 或此处:GreyCat's Wiki: XyProblem)– 您试图将数据放入树结构中,只是因为它们的呈现方式类似于一个树状的金字塔,但您没有检查这种结构是否真的可以帮助您解决问题。

    答案是:不,不会;它甚至不符合实际的问题结构。

    你的问题结构是一个金字塔状的整数三角形,每个三角形都有两个最近的后代(底行除外)和两个最近的祖先(只有一个祖先的侧边除外),并且顶部项目,根本没有祖先)。而且您已经通过“三角公式”将该结构映射到线性数组中:

    给定行号r0 .. N-1 的范围内和行中的位置p0 .. r 的范围内和一个索引为0 .. N*(N+1)/2-1 的数组, 项目(r,p) 存储在索引r*(r+1)/2 + p 的数组中,
    及其“孩子”是(r+1,p)(r+1,p+1)

    就是这样,映射允许您以“三角形”方式访问数据,您不需要树来处理它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多