从给定的后序遍历中构建一个完整的N-ary树

144 阅读5分钟

从给定的后序遍历中构建一个完整的N-ary树

改进文章

保存文章

喜欢的文章

  • 最后更新: 2022年6月3日

给定一个大小为M数组 arr[],其中包含完整的N-ary树的后序遍历,任务是生成N-ary树并打印其前序遍历。

一棵完整的树是指树的所有层次都被完全填满,除了可能是最后一个层次,但最后一个层次的节点是尽可能的左边。

例子。

**输入:**arr[] = {5, 6, 7, 2, 8, 9, 3, 4, 1}, N = 3
输出

Example-1

上述例子的树状结构

**输入:**arr[] = {7, 8, 9, 2, 3, 4, 5, 6, 1}, N = 5
输出

Example 2

第二个例子的完整结构

**办法。**解决该问题的方法是基于以下关于完整的N-ary树的事实。

假设完整的N-ary树的任何一棵子树都有一个高度H。

前H层的节点总数为N0+N1+N2+ ... ...+NH-1=(NH- 1)/(N - 1)。

最后一级的最大可能节点是NH
因此,如果子树的最后一层至少有NH个节点,那么子树最后一层的总节点是(NH- 1)/(N - 1) +NH

高度H可以计算为ceil[logN( M*(N-1) +1)] - 1,因为
N-ary完整二叉树,最多可以有**(NH+1**- 1)/(N - 1)] 个节点。

由于给定的数组包含后序遍历,数组的最后一个元素将总是根节点。现在基于上述观察,剩余的数组可以被划分为该节点的若干个子树。

按照下面提到的步骤来解决这个问题。

  1. 数组的最后一个元素是树的根。
  2. 现在把剩下的数组分成子数组,这些子数组代表每个子树的节点总数。
  3. 每个子树的高度肯定是H-2,根据上述观察,如果任何子树有超过**(NH-1 -1)/(N - 1)个节点,那么它的高度是H-1**。
  4. 要计算子树的节点数,请遵循以下案例。
    • 如果最后一级有超过NH-1的节点,那么这个子树的所有级别都是满的,子树有**(NH-1-1)/(N-1)+NH-1的**节点。
    • 否则,该子树将有**(NH-1**-1)/(N-1)+L个节点,其中L是最后一级的节点数。
    • L可以计算为L = M - (NH- 1)/(N - 1)。
  5. 为了生成每个子阵列,重复应用第2到第4步,对每个子树的大小(M)和高度(H)进行相应调整。
  6. 返回以这种方式形成的树的预排序遍历

为了更好地理解,请看下面的插图

插图。

考虑这个例子:arr[] = {5, 6, 7, 2, 8, 9, 3, 4, 1},N = 3。

所以高度(H)= ceil[log3(9*2+1)] - 1 = ceil[log319] - 1 = 3 - 1 = 2,L = 9 - (32- 1)/2 = 5。

**第1步。**所以根=1

1st step of forming the tree

形成树的第1步

**第2步。**剩余的数组将被分解成子树。对于第一个子树H=2。
5>32-1,即L>3。所以最后一层完全被填满,第一个子树的节点数=(3-1)/2+3=4[用上面的公式计算]。

第一个子树包含的元素={5,6,7,2}。剩下的部分是{8,9,3,4}
,子树的根=2。

现在,当用同样的方法计算5、6、7的子树时,它们没有任何子节点,本身就是叶节点。

2nd step of generating the tree

生成树的第二步

**第3步。**现在L被更新为2。
2 < 3。所以使用上述公式,第二个子树的节点数为1 + 2 = 3。

所以第二棵子树的元素是{8, 9, 3},剩下的部分是{4},3是第二棵子树的根。

3nd step of generating the tree

生成树的第3步

**第四步。**现在L=0,子树的唯一元素是{4}本身。

final structure of tree

树的最终结构

这一步之后,树就完全建成了。

下面是上述方法的实现。

C++

// C++ code to implement the aproach
#include <bits/stdc++.h>
using namespace std;
// Node Class
template <typename T>class Node {
public:
Node(T data);
// Get the first child of the Node
Node* get_first_child()const;
// Get the Next Sibling of The node
Node* get_next_sibling()const;
// Sets the next sibling of the node
void set_next_sibling(Node* node);
// Sets the next child of the node
void set_next_child(Node* node);
// Returns the data the node contains
T get_data();
private:
T data;
// We use the first child/next sibling representation
// to represent the Tree
Node* first_child;
Node* next_sibling;
};
// Using template for generic usage
template <typename T> Node<T>::Node(T data)
{
first_child = NULL;
next_sibling = NULL;
this->data = data;
}
// Function to get the first child
template <typename T>
Node<T>* Node<T>::get_first_child()const
{
return first_child;
}
// Function to get the siblings
template <typename T>
Node<T>* Node<T>::get_next_sibling()const
{
return next_sibling;
}
// Function to set next sibling
template <typename T>
void Node<T>::set_next_sibling(Node<T>* node)
{
if (next_sibling == NULL) {
next_sibling = node;
}
else {
next_sibling->set_next_sibling(node);
}
}
// Function to get the data
template <typename T> T Node<T>::get_data() {return data; }
// Function to set the child node value
template <typename T>
void Node<T>::set_next_child(Node<T>* node)
{
if (first_child == NULL) {
first_child = node;
}
else {
first_child->set_next_sibling(node);
}
}
// Function to construct the tree
template <typename T>
Node<T>* Construct(T* post_order_arr,int size,int k)
{
Node<T>* Root =new Node<T>(post_order_arr[size - 1]);
if (size == 1) {
return Root;
}
int height_of_tree
=ceil(log2(size * (k - 1) + 1) / log2(k)) - 1;
int nodes_in_last_level
= size - ((pow(k, height_of_tree) - 1) / (k - 1));
int tracker = 0;
while (tracker != (size - 1)) {
int last_level_nodes
= (pow(k, height_of_tree - 1)
> nodes_in_last_level)
? nodes_in_last_level
: (pow(k, height_of_tree - 1));
int nodes_in_next_subtree
= ((pow(k, height_of_tree - 1) - 1) / (k - 1))
+ last_level_nodes;
Root->set_next_child(
Construct(post_order_arr + tracker,
nodes_in_next_subtree, k));
tracker = tracker + nodes_in_next_subtree;
nodes_in_last_level
= nodes_in_last_level - last_level_nodes;
}
return Root;
}
// Function to print the preorder traversal
template <typename T>void preorder(Node<T>* Root)
{
if (Root == NULL) {
return;
}
cout << Root->get_data() <<" ";
preorder(Root->get_first_child());
preorder(Root->get_next_sibling());
}
// Driver code
int main()
{
int M = 9, N = 3;
int arr[] = { 5, 6, 7, 2, 8, 9, 3, 4, 1 };
// Function call
preorder(Construct(arr, M, N));
return 0;
}

输出

1  2  5  6  7  3  8  9  4  

**时间复杂度。**O(M)
**辅助空间。**O(M)用于构建树

我的个人笔记arrow_drop_up

保存