计算树遍历的最大堆栈大小

时间:2020-04-01 15:53:26

标签: algorithm tree tree-traversal space-complexity

我为n元树实现了树遍历算法,该算法遵循预排序并使用堆栈而不是递归。在伪代码中,算法如下所示:

  • 创建一个空堆栈stack并将根节点压入堆栈。
  • stack不为空时执行以下操作。
    • stack弹出项目并打印。可选:如果是人工端节点,请继续
    • 可选:将人工节点node_end推到stack
    • 将所有孩子从右向左推到stack

可选部分用于一个用例,其中我打印一个保留为树结构的XML文档。访问节点X将打印开始标签,访问人工节点X_end将打印相应的结束标签。

这里的绘制很粗糙,所以我用C ++代码给出了这棵树。

struct Node {
    int id; // root is 0
    std::vector<int> children; // index in the vector
}

std::array<Node, 15> tree{};

// sets all the ids, in total we have 15 nodes
for (int i = 0; i < 15; ++i)
    tree[i].id = i;

// now all the children, hope one can see the tree structure
tree[0].children.push_back(1);
tree[0].children.push_back(6);
tree[1].children.push_back(2);
tree[1].children.push_back(3);
// 2 is a leaf
tree[3].children.push_back(4);
tree[3].children.push_back(5);
// 4 is a leaf
// 5 is a leaf
tree[6].children.push_back(7);
tree[6].children.push_back(9);
tree[6].children.push_back(12);
tree[7].children.push_back(8);
// 8 is a leaf
tree[9].children.push_back(10);
tree[9].children.push_back(11);
// 10 is a leaf
// 11 is a leaf
tree[12].children.push_back(13);
tree[12].children.push_back(13);
// 13 is a leaf
// 14 is a leaf

现在,运行上述算法将得到以下堆栈(一个带有人工末端节点,另一个不带有人工末端节点):

current_node | stack (simple version)
---------------------------------
      -      | 0
      0      | 6,1
      1      | 6,3,2
      2      | 6,3
      3      | 6,5,4
      4      | 6,5
      5      | 6
      6      | 12,9,7
      7      | 12,9,8
      8      | 12,9
      9      | 12,11,10
      10     | 12,11
      11     | 12
      12     | 14,13
      13     | 14
      14     | -

第二个:

current_node | stack (with end nodes)
---------------------------------
      -      | 0
      0      | 0e,6,1
      1      | 0e,6,1e,3,2
      2      | 0e,6,1e,3,2e
      2      | 0e,6,1e,3
      3      | 0e,6,1e,3e,5,4
      4      | 0e,6,1e,3e,5,4e
      4      | 0e,6,1e,3e,5
      5      | 0e,6,1e,3e,5e
      5      | 0e,6,1e,3e
      3      | 0e,6,1e
      1      | 0e,6
      6      | 0e,6e,12,9,7
      7      | 0e,6e,12,9,7e,8
      8      | 0e,6e,12,9,7e,8e
      8      | 0e,6e,12,9,7e
      7      | 0e,6e,12,9
      9      | 0e,6e,12,9e,11,10
      10     | 0e,6e,12,9e,11,10e
      10     | 0e,6e,12,9e,11
      11     | 0e,6e,12,9e,11e
      11     | 0e,6e,12,9e
      9      | 0e,6e,12
      12     | 0e,6e,12e,14,13
      13     | 0e,6e,12e,14,13e
      13     | 0e,6e,12e,14
      14     | 0e,6e,12e,14e
      14     | 0e,6e,12e
      12     | 0e,6e
      6      | 0e
      0      | -

我真的希望我没有打错字。如果出现问题,请通知我。

现在我的问题是:出于优化目的,最好事先知道堆栈的最大大小。我发现以下公式可以计算单个节点所需的大小。

简单版本:

int getRequiredStackSize(Node node)
{
    int sum = 0;
    sum += node.children.size();
    sum += getNumOfRightSiblings(node);
    for (Node parent = getParent(Node); parent != NULL; parent = getParent(parent))
        sum += getNumOfRightSiblings(parent);
    return sum;
}

总体最大堆栈大小是所有节点的最大堆栈大小。也许可以用更少的计算来完成?

第二种情况:

int getRequiredStackSize(Node node)
{
    int sum = 1; // the node's own artifical end node
    sum += node.children.size();
    sum += getNumOfRightSiblings(node);
    for (Node parent = getParent(Node); parent != NULL; parent = getParent(parent))
        sum += (1 + getNumOfRightSiblings(parent)); // the parents artifical end node as well
    return sum;
}

在这里,我认为可以只计算每组兄弟姐妹中最左边的叶子的值(如何称呼同一亲代下的一组叶子?)并取其中的最大值。

第一个问题:是否可以对这些公式进行优化?

第二个问题:如何有效地计算最大值?注意:我确实自己构造了树,所以可以保留计数器等。

0 个答案:

没有答案