📜  从祖先矩阵构造树

📅  最后修改于: 2022-05-13 01:57:19.914000             🧑  作者: Mango

从祖先矩阵构造树

给定一个祖先矩阵 mat[n][n],其中祖先矩阵定义如下。

mat[i][j] = 1 if i is ancestor of j
mat[i][j] = 0, otherwise

从给定的祖先矩阵构造一棵二叉树,其中所有节点的值都从 0 到 n-1。

  1. 可以假设提供程序的输入是有效的,并且可以从中构造树。
  2. 许多二叉树可以从一个输入构建。该程序将构建其中任何一个。

例子:

Input: 0 1 1
       0 0 0 
       0 0 0 
Output: Root of one of the below trees.
    0                0
  /   \     OR     /   \
 1     2          2     1

Input: 0 0 0 0 0 0 
       1 0 0 0 1 0 
       0 0 0 1 0 0 
       0 0 0 0 0 0 
       0 0 0 0 0 0 
       1 1 1 1 1 0
Output: Root of one of the below trees.
      5              5               5
   /    \           / \            /   \
  1      2   OR    2   1    OR    1     2  OR ....
 /  \   /        /    /  \       / \    /
0   4  3        3    0    4     4   0  3
There are different possible outputs because ancestor
matrix doesn't store that which child is left and which
is right.

我们强烈建议您最小化您的浏览器并首先自己尝试。

解决方案中使用的观察结果:

  1. 与叶子对应的行全为 0
  2. 对应于根的行的最大数量为 1。
  3. 第 i 行中 1 的计数表示节点 i 的后代数。

这个想法是以自下而上的方式构建树。

  1. 创建一个节点指针数组 node[]。
  2. 存储与给定计数对应的行号。为此,我们使用了 multimap。
  3. 处理 multimap 的所有条目从最小计数到最大计数(注意 map 和 multimap 中的条目可以按排序顺序遍历)。对每个条目进行以下操作。
    • 为当前行号创建一个新节点。
    • 如果该节点不是叶节点,则考虑它的所有未设置父节点的后代,将当前节点作为其父节点。
  4. 最后处理的节点(具有最大和的节点)是树的根。

下面是上述方法的实现:

C++
// Given an ancestor matrix for binary tree, construct
// the tree.
#include 
using namespace std;
   
# define N 6
   
/* A binary tree node */
struct Node
{
    int data;
    Node *left, *right;
};
   
/* Helper function to create a new node */
Node* newNode(int data)
{
    Node* node = new Node;
    node->data = data;
    node->left = node->right = NULL;
    return (node);
}
   
// Constructs tree from ancestor matrix
Node* ancestorTree(int mat[][N])
{
    // Binary array to determine whether
    // parent is set for node i or not
    int parent[N] = {0};
   
    // Root will store the root of the constructed tree
    Node* root = NULL;
   
    // Create a multimap, sum is used as key and row
    // numbers are used as values
    multimap mm;
   
    for (int i = 0; i < N; i++)
    {
        int sum = 0; // Initialize sum of this row
        for (int j = 0; j < N; j++)
            sum += mat[i][j];
   
        // insert(sum, i) pairs into the multimap
        mm.insert(pair(sum, i));
    }
   
    // node[i] will store node for i in constructed tree
    Node* node[N];
   
    // Traverse all entries of multimap.  Note that values
    // are accessed in increasing order of sum
    for (auto it = mm.begin(); it != mm.end(); ++it)
    {
      // create a new node for every value
      node[it->second] = newNode(it->second);
   
      // To store last processed node. This node will be
      // root after loop terminates
      root = node[it->second];
   
      // if non-leaf node
      if (it->first != 0)
      {
        // traverse row 'it->second' in the matrix
        for (int i = 0; i < N; i++)
        {
           // if parent is not set and ancestor exits
           if (!parent[i] && mat[it->second][i])
           {
             // check for unoccupied left/right node
             // and set parent of node i
             if (!node[it->second]->left)
               node[it->second]->left = node[i];
             else
               node[it->second]->right = node[i];
   
             parent[i] = 1;
           }
        }
      }
    }
    return root;
}
   
/* Given a binary tree, print its nodes in inorder */
void printInorder(Node* node)
{
    if (node == NULL)
        return;
    printInorder(node->left);
    printf("%d ", node->data);
    printInorder(node->right);
}
   
// Driver code
int main()
{
    int mat[N][N] = {{ 0, 0, 0, 0, 0, 0 },
        { 1, 0, 0, 0, 1, 0 },
        { 0, 0, 0, 1, 0, 0 },
        { 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0 },
        { 1, 1, 1, 1, 1, 0 }
    };
   
    Node* root = ancestorTree(mat);
   
    cout << "Inorder traversal of tree is \n";
     
    // Function call
    printInorder(root);
   
    return 0;
}


Java
// Given an ancestor matrix for binary tree, construct
// the tree.
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
 
/* A binary tree node */
class Node {
    int data;
    Node left, right;
 
    Node(int d)
    {
        data = d;
        left = right = null;
    }
}
 
public class TreeFromAncestorMatrix {
 
    static Node ancestorNode(int[][] mat)
    {
        int n = mat.length;
 
        // Binary array to determine whether parent is set
        // for node i or not
        int[] parent = new int[n];
        Node root = null;
 
        // Map to store row numbers as key and
        // their sum as their values
        Map map = new HashMap<>();
 
        for (int i = 0; i < n; i++) {
            int sum = 0;
 
            for (int j = 0; j < n; j++)
                sum += mat[i][j];
 
            map.put(i, sum);
        }
 
        // node[i] will store node for i in
        //constructed tree
        Node node[] = new Node[n];
 
        // Sorting the map according to its
        //values
        Map sorted
            = map.entrySet()
                  .stream()
                  .sorted(Map.Entry.comparingByValue())
                  .collect(Collectors.toMap(
                      e
                      -> e.getKey(),
                      e
                      -> e.getValue(),
                      (e1, e2) -> e2, LinkedHashMap::new));
 
        // Traverse all entries of sorted Map.
        // Note that values are accessed in increasing order
        // of sum
        for (Map.Entry entry :
             sorted.entrySet()) {
            int key = entry.getKey();
            int value = entry.getValue();
 
            // create a new node for every
            // value
            node[key] = new Node(key);
 
            // if its is an internal node
            if (value != 0) {
 
                // Traverse row
                //corresponding to the node
                for (int i = 0; i < n; i++)
                {
 
                    // if parent is not set and
                    //ancestor exits
                    if (parent[i] == 0
                        && mat[key][i] != 0)
                    {
                        // check for unoccupied
                        // left/right node and
                        //set parent of node i
                        if (node[key].left == null)
                            node[key].left = node[i];
                        else
                            node[key].right = node[i];
                        parent[i] = 1;
                    }
 
                    // To store last processed
                    // node. This node will be root after
                    // loop terminates
                    root = node[key];
                }
            }
        }
 
        return root;
    }
  
    /* Given a binary tree, print its nodes in inorder */
    static void inOrder(Node root)
    {
        if (root == null)
            return;
        inOrder(root.left);
        System.out.print(root.data + " ");
        inOrder(root.right);
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int mat[][] = {
            { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0 },
            { 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 1, 1, 0 }
        };
 
        Node root = ancestorNode(mat);
 
         // Function call
        inOrder(root);
    }
}
 
// contribute by amarsomani


Python3
# key structure to store a binary tree node
class Node:
    def __init__(self, key, left = None, right = None):
        self.key = key
        self.left = left
        self.right = right
 
# Utility function to print binary tree nodes in-order fashion
def inorder(node):
    if node:
        inorder(node.left)
        print(node.key, end = ' ')
        inorder(node.right)
 
# Function to construct a binary tree
# from specified ancestor matrix
def constructBT(mat):
   
    # get number of rows in the matrix
    N = len(mat)
 
    # create an empty multi-dict
    dict = {}
 
    # Use sum as key and row numbers as values in the multi-dict
    for i in range(N):
 
        # find the sum of the current row
        total = sum(mat[i])
 
        # insert the sum and row number into the dict
        dict.setdefault(total, []).append(i)
 
    # node[i] will store node for i in constructed tree
    node = [Node(-1)] * N
    last = 0
 
    # the value of parent[i] is true if parent is set for i'th node
    parent = [False] * N
 
    # Traverse the dictionary in sorted order (default behavior)
    for key in dict.keys():
        for row in dict.get(key):
            last = row
             
            # create a new node
            node[row] = Node(row)
 
            # if leaf node, do nothing
            if key == 0:
                continue
 
            # traverse row
            for i in range(N):
               
                # do if parent is not set and ancestor exits
                if not parent[i] and mat[row][i] == 1:
                   
                    # check for the unoccupied node
                    if node[row].left is None:
                        node[row].left = node[i]
                    else:
                        node[row].right = node[i]
 
                    # set parent for i'th node
                    parent[i] = True
 
    # last processed node is the root
    return node[last]
 
# Construct a Binary Tree from Ancestor Matrix
if __name__ == '__main__':
 
    mat = [[0, 0, 0, 0, 0, 0],
        [1, 0, 0, 0, 1, 0],
        [0, 0, 0, 1, 0, 0],
        [0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0],
        [1, 1, 1, 1, 0, 0]]
 
    root = constructBT(mat)
    inorder(root)
 
# This code is contributed by Priyadarshini Kumari


C#
// Given an ancestor matrix for binary tree, construct
// the tree.
using System;
using System.Collections.Generic;
using System.Linq;
 
/* A binary tree node */
public
  class Node
  {
    public
      int data;
    public
      Node left, right;
    public
      Node(int d)
    {
      data = d;
      left = right = null;
    }
  }
 
public class TreeFromAncestorMatrix
{
 
  static Node ancestorNode(int[,] mat)
  {
    int n = mat.GetLength(0);
 
    // Binary array to determine whether parent is set
    // for node i or not
    int[] parent = new int[n];
    Node root = null;
 
    // Map to store row numbers as key and
    // their sum as their values
    Dictionary map = new Dictionary();
    for (int i = 0; i < n; i++)
    {
      int sum = 0;
      for (int j = 0; j < n; j++)
        sum += mat[i, j];
      map.Add(i, sum);
    }
 
    // node[i] will store node for i in
    //constructed tree
    Node []node = new Node[n];
 
    var sorted = from entry in map orderby entry.Value ascending select entry;
 
    // Traverse all entries of sorted Map.
    // Note that values are accessed in increasing order
    // of sum
    foreach (KeyValuePair entry in
             sorted)
    {
      int key = entry.Key;
      int value = entry.Value;
 
      // create a new node for every
      // value
      node[key] = new Node(key);
 
      // if its is an internal node
      if (value != 0)
      {
 
        // Traverse row
        //corresponding to the node
        for (int i = 0; i < n; i++)
        {
 
          // if parent is not set and
          //ancestor exits
          if (parent[i] == 0
              && mat[key,i] != 0)
          {
            // check for unoccupied
            // left/right node and
            //set parent of node i
            if (node[key].left == null)
              node[key].left = node[i];
            else
              node[key].right = node[i];
            parent[i] = 1;
          }
 
          // To store last processed
          // node. This node will be root after
          // loop terminates
          root = node[key];
        }
      }
    }
    return root;
  }
 
  /* Given a binary tree, print its nodes in inorder */
  static void inOrder(Node root)
  {
    if (root == null)
      return;
    inOrder(root.left);
    Console.Write(root.data + " ");
    inOrder(root.right);
  }
 
  // Driver code
  public static void Main(String[] args)
  {
    int [,]mat = {
      { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0 },
      { 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0 },
      { 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 1, 1, 0 }
    };
    Node root = ancestorNode(mat);
 
    // Function call
    inOrder(root);
  }
}
 
// This code is contributed by Rajput-Ji


Javascript


输出
0 1 4 5 3 2

请注意,我们还可以使用向量数组来代替 multimap。为简单起见,我们使用了多图。向量数组将提高性能,因为插入和访问元素将花费 O(1) 时间。