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

83 阅读5分钟

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

给定一个大小为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 approach

#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;
}

Java

// Java code to implement the approach

import java.io.*;
import java.util.*;

class GFG
{

// Function to calculate the
// log base 2 of an integer
public static int log2(int N)
{

	// calculate log2 N indirectly
	// using log() method
	int result = (int)(Math.log(N) / Math.log(2));

	return result;
}

// Node Class
public static class Node {
	int data;

	// We use the first child/next sibling
	// representation to represent the Tree
	Node first_child;
	Node next_sibling;

	// Initiallizing Node using Constructor
	public Node(int data)
	{
	this.first_child = null;
	this.next_sibling = null;
	this.data = data;
	}

	// Function to get the first child
	public Node get_first_child()
	{
	return this.first_child;
	}

	// Function to get the siblings
	public Node get_next_sibling()
	{
	return this.next_sibling;
	}

	// Function to set the next sibling
	public void set_next_sibling(Node node)
	{
	if (this.next_sibling == null) {
		this.next_sibling = node;
	}
	else {
		this.next_sibling.set_next_sibling(node);
	}
	}

	// Function to get the data
	public int get_data() { return this.data; }

	// Function to set the child node values
	public void set_next_child(Node node)
	{
	if (this.first_child == null) {
		this.first_child = node;
	}
	else {
		this.first_child.set_next_sibling(node);
	}
	}
}

public static void main(String[] args)
{
	int M = 9, N = 3;
	int[] arr = { 5, 6, 7, 2, 8, 9, 3, 4, 1 };

	// Function call
	preorder(Construct(arr, 0, M, N));
}

// Function to print the preorder traversal
public static void preorder(Node Root)
{
	if (Root == null) {
	return;
	}
	System.out.println(Root.get_data() + " ");
	preorder(Root.get_first_child());
	preorder(Root.get_next_sibling());
}

// Function to construct the tree
public static Node Construct(int[] post_order_arr,
							int tracker, int size,
							int k)
{
	Node Root = new Node(post_order_arr[tracker+size - 1]);
	if (size == 1) {
	return Root;
	}
	int height_of_tree
	= (int)Math.ceil(log2(size * (k - 1) + 1)
					/ log2(k))
	- 1;
	int nodes_in_last_level
	= size
	- (((int)Math.pow(k, height_of_tree) - 1)
		/ (k - 1));
	int x=tracker;
	while (tracker != (size - 1)) {
	int last_level_nodes
		= ((int)Math.pow(k, height_of_tree - 1)
		> nodes_in_last_level)
		? nodes_in_last_level
		: ((int)Math.pow(k,
						height_of_tree - 1));
	int nodes_in_next_subtree
		= (((int)Math.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;
}
}

输出

1  2  5  6  7  3  8  9  4  

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