【问题标题】:How to construct a tree given its depth and postorder traversal, then print its preorder traversal如何在给定深度和后序遍历的情况下构造一棵树,然后打印其前序遍历
【发布时间】:2021-07-14 08:14:57
【问题描述】:

我需要构造一棵给定深度和后序遍历的树,然后我需要生成对应的前序遍历。示例:

Depth: 2 1 3 3 3 2 2 1 1 0
Postorder: 5 2 8 9 10 6 7 3 4 1
Preorder(output): 1 2 5 3 6 8 9 10 7 4

我定义了两个包含后序序列和深度的数组。在那之后,我想不出一个算法来解决它。

这是我的代码:

int postorder[1000];
int depth[1000];
string postorder_nums;
getline(cin, postorder_nums);
istringstream token1(postorder_nums);
string tokenString1;
int idx1 = 0;
while (token1 >> tokenString1) {
    postorder[idx1] = stoi(tokenString1);
    idx1++;
}
string depth_nums;
getline(cin, depth_nums);
istringstream token2(depth_nums);
string tokenString2;
int idx2 = 0;
while (token2 >> tokenString2) {
    depth[idx2] = stoi(tokenString2);
    idx2++;
}
Tree tree(1);

【问题讨论】:

  • 您的树代码不存在...将数字读取为字符串然后将这些字符串转换为数字是没有意义的。至于主要任务:尝试在一张纸上画树。然后,尝试想出一个可以容纳树的数据结构。深思:它是二叉树还是更复杂的东西?你会使用指针还是构建扁平树?
  • 它不是二叉树,它只是一棵可以有三个或更多孩子的普通树。我会再次检查我的问题并感谢您的评论。

标签: c++ algorithm tree preorder postorder


【解决方案1】:

您实际上可以在不构建树的情况下做到这一点。

首先请注意,如果您反转后序序列,您会得到一种前序序列,但访问的孩子顺序相反。所以我们将使用这个事实并从后到前迭代给定的数组,我们还将从后到前将值存储在输出中。这样至少兄弟姐妹的顺序会正确。

因此,我们从输入中获得的第一个值将始终是根值。显然我们不能将此值存储在输出数组的末尾,因为它确实应该排在第一位。但是我们将把这个值放在一个堆栈上,直到所有其他值都被处理完。对于后面跟着“更深”值的任何值都会发生同样的情况(同样:我们正在以相反的顺序处理输入)。但是一旦我们找到一个不深的值,我们就会将堆栈的一部分刷新到输出数组中(也从后到前填充它)。

当所有的值都被处理完后,我们只需要将剩余的值从栈中刷新到输出数组中。

现在,我们可以在这里优化我们的空间使用:当我们从后面填充输出数组时,我们在其前面有空闲空间用作该算法的堆栈空间。这样做的好处是,当我们到达末尾时,我们不再需要刷新堆栈,因为它已经在输出中,每个值都应该在。

这里是这个算法的代码,我没有包含输入集合,显然你已经在工作了:

// Input example
int depth[] = {2, 1, 3, 3, 3, 2, 2, 1, 1, 0};
int postorder[] = {5, 2, 8, 9, 10, 6, 7, 3, 4, 1};
// Number of values in the input
int n = sizeof(depth)/sizeof(int);

int preorder[n]; // This will contain the ouput
int j = n; // index where last value was stored in preorder
int stackSize = 0; // how many entries are used as stack in preorder
for (int i = n - 1; i >= 0; i--) {
    while (depth[i] < stackSize) {
        preorder[--j] = preorder[--stackSize]; // flush it
    }
    preorder[stackSize++] = postorder[i]; // stack it
}
// Output the result:
for (int i = 0; i < n; i++) {
    std::cout << preorder[i] << " ";
}
std::cout << "\n";

该算法的辅助空间复杂度为 O(1)——因此不计算输入和输出所需的内存——并且时间复杂度为 O(n)。

【讨论】:

  • 你成就了我的一天!
【解决方案2】:

我不会给你代码,但是一些提示如何解决这个问题。

首先,对于后序图处理,您首先访问子节点,然后打印(处理)节点的值。因此,树或子树父是在其(子)树中处理的最后一件事。我将 10 替换为 0 以获得更好的缩进:

2 1 3 3 3 2 2 1 1 0
--------------------
5 2 8 9 0 6 7 3 4 1

如上所述,深度为 0 的节点或根是最后一个。让我们将所有其他节点降低 1 级:

2 1 3 3 3 2 2 1 1 0
-------------------
                  1
5 2 8 9 0 6 7 3 4 

现在识别深度为 1 的所有节点,并降低所有深度不为 0 或 1 的节点:

2 1 3 3 3 2 2 1 1 0
-------------------
                  1
  2           3 4 
5   8 9 0 6 7 

如您所见,(5,2) 在一个子树中,(8,9,10,6,7,3) 在另一个子树中,(4) 是单节点子树。换句话说,2的左边都是它的子树,2的右边和3的左边都是3的子树,3到4之间的都是4的子树(这里:空)。

现在让我们以类似的方式处理深度 3:

2 1 3 3 3 2 2 1 1 0
-------------------
                  1
  2           3 4 
5         6 7 
    8 9 0  
  • 2 是 2 的父代;
  • 6 是 8、8、10 的父代;
  • 3 是 6,7 的父级;

或非常明确:

2 1 3 3 3 2 2 1 1 0
-------------------
                  1
   /           / /
  2           3 4 
 /         / /
5         6 7 
     / / /
    8 9 0  

这就是你可以从你拥有的数据中构造一棵树的方法。

编辑

显然,这个问题可以通过递归轻松解决。在每个步骤中,您找到最低深度,打印节点,并为其每个子树递归调用相同的函数作为其参数,其中子树是通过查找 current_depth + 1 来定义的。如果深度作为另一个参数传递,它可以省去计算最低深度的必要性。

【讨论】:

  • 这个方法似乎不错,谢谢。
猜你喜欢
  • 1970-01-01
  • 2012-10-21
  • 2011-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多