📜  将任意二叉树转换为包含 Children Sum 属性的树

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

将任意二叉树转换为包含 Children Sum 属性的树

问题:给定一棵任意二叉树,将其转换为具有 Children Sum 属性的二叉树。您只能增加任何节点中的数据值(您不能更改树的结构,也不能减少任何节点的值)。
例如,下面的树不包含子 sum 属性,将其转换为包含该属性的树。

50
           /     \     
         /         \
       7             2
     / \             /\
   /     \          /   \
  3        5      1      30

算法:
以后序遍历给定的树进行转换,即先改变左右子节点以保持子节点和属性,然后改变父节点。
让节点数据和子节点总和之间的差异为差异。

diff = node’s children sum - node’s data  

如果 diff 为 0,则无需执行任何操作。
如果 diff > 0(节点的数据小于节点的子节点总和)将节点的数据增加 diff。
如果 diff < 0(节点的数据大于节点的子节点总和),则增加一个子节点的数据。如果它们都不是NULL,我们可以选择增加左或右孩子。让我们总是首先增加左孩子。增加一个孩子会改变子树的孩子总和属性,所以我们也需要改变左子树。所以我们递归地增加左孩子。如果左孩子为空,那么我们递归地为右孩子调用 increment()。
让我们运行给定示例的算法。
首先转换左子树(增量 7 到 8)。

50
           /     \     
         /         \
       8             2
     / \             /\
   /     \          /   \
  3        5      1      30

然后转换右子树(增量2到31)

50
        /    \     
      /        \
    8            31
   / \           / \
 /     \       /     \
3       5    1       30

现在转换根,我们必须增加左子树来转换根。

50
        /    \     
      /        \
    19           31
   / \           /  \
 /     \       /      \
14      5     1       30

请注意最后一步——我们将 8 增加到 19,为了修复子树,我们将 3 增加到 14。
执行:

C++
/* C++ Program to convert an arbitrary
binary tree to a tree that hold
children sum property */
#include
using namespace std;
 
class node
{
    public:
    int data;
    node* left;
    node* right;
     
    /* Constructor that allocates a new node
    with the given data and NULL left and right
    pointers. */
    node(int data)
    {
        this->data = data;
        this->left = NULL;
        this->right = NULL;
    }
};
 
/* This function is used
to increment left subtree */
void increment(node* node, int diff);
 
/* This function changes a tree
to hold children sum property */
void convertTree(node* node)
{
    int left_data = 0, right_data = 0, diff;
     
    /* If tree is empty or it's a leaf 
        node then return true */
    if (node == NULL || (node->left == NULL &&
                        node->right == NULL))
        return;
    else
    {
        /* convert left and right subtrees */
        convertTree(node->left);
        convertTree(node->right);
     
        /* If left child is not present then 0 is used
        as data of left child */
        if (node->left != NULL)
        left_data = node->left->data;
     
        /* If right child is not present then 0 is used
        as data of right child */
        if (node->right != NULL)
        right_data = node->right->data;
     
        /* get the diff of node's data and children sum */
        diff = left_data + right_data - node->data;
     
        /* If node's children sum is
        greater than the node's data */
        if (diff > 0)
        node->data = node->data + diff;
     
        /* THIS IS TRICKY --> If node's data
        is greater than children sum,
        then increment subtree by diff */
        if (diff < 0)
        increment(node, -diff); // -diff is used to make diff positive
    }
}
 
/* This function is used
to increment subtree by diff */
void increment(node* node, int diff)
{
    /* IF left child is not
    NULL then increment it */
    if(node->left != NULL)
    {
        node->left->data = node->left->data + diff;
     
        // Recursively call to fix
        // the descendants of node->left
        increment(node->left, diff);
    }
    else if (node->right != NULL) // Else increment right child
    {
        node->right->data = node->right->data + diff;
     
        // Recursively call to fix
        // the descendants of node->right
        increment(node->right, diff);
    }
}
 
/* Given a binary tree,
printInorder() prints out its
inorder traversal*/
void printInorder(node* node)
{
    if (node == NULL)
        return;
     
    /* first recur on left child */
    printInorder(node->left);
     
    /* then print the data of node */
    cout<data<<" ";
     
    /* now recur on right child */
    printInorder(node->right);
}
 
/* Driver code */
int main()
{
    node *root = new node(50);
    root->left = new node(7);
    root->right = new node(2);
    root->left->left = new node(3);
    root->left->right = new node(5);
    root->right->left = new node(1);
    root->right->right = new node(30);
     
    cout << "\nInorder traversal before conversion: " << endl;
    printInorder(root);
     
    convertTree(root);
     
    cout << "\nInorder traversal after conversion: " << endl;
    printInorder(root);
    return 0;
}
 
// This code is contributed by rathbhupendra


C
/* Program to convert an arbitrary binary tree to
   a tree that holds children sum property */
 
#include 
#include 
 
struct node
{
  int data;
  struct node* left;
  struct node* right;
};
 
/* This function is used to increment left subtree */
void increment(struct node* node, int diff);
 
/* Helper function that allocates a new node
 with the given data and NULL left and right
 pointers. */
struct node* newNode(int data);
 
/* This function changes a tree to hold children sum
   property */
void convertTree(struct node* node)
{
  int left_data = 0,  right_data = 0, diff;
 
  /* If tree is empty or it's a leaf node then
     return true */
  if (node == NULL ||
     (node->left == NULL && node->right == NULL))
    return;
  else
  {
    /* convert left and right subtrees  */
    convertTree(node->left);
    convertTree(node->right);
 
    /* If left child is not present then 0 is used
       as data of left child */
    if (node->left != NULL)
      left_data = node->left->data;
 
    /* If right child is not present then 0 is used
      as data of right child */
    if (node->right != NULL)
      right_data = node->right->data;
 
    /* get the diff of node's data and children sum */
    diff = left_data + right_data - node->data;
 
    /* If node's children sum is greater than the node's data */
    if (diff > 0)
       node->data = node->data + diff;
 
    /* THIS IS TRICKY --> If node's data is greater than children sum,
      then increment subtree by diff */
    if (diff < 0)
      increment(node, -diff);  // -diff is used to make diff positive
  }
}
 
/* This function is used to increment subtree by diff */
void increment(struct node* node, int diff)
{
  /* IF left child is not NULL then increment it */
  if(node->left != NULL)
  {
    node->left->data = node->left->data + diff;
 
    // Recursively call to fix the descendants of node->left
    increment(node->left, diff); 
  }
  else if (node->right != NULL) // Else increment right child
  {
    node->right->data = node->right->data + diff;
 
    // Recursively call to fix the descendants of node->right
    increment(node->right, diff);
  }
}
 
/* Given a binary tree, printInorder() prints out its
   inorder traversal*/
void printInorder(struct node* node)
{
  if (node == NULL)
    return;
 
  /* first recur on left child */
  printInorder(node->left);
 
  /* then print the data of node */
  printf("%d ", node->data);
 
  /* now recur on right child */
  printInorder(node->right);
}
 
/* Helper function that allocates a new node
 with the given data and NULL left and right
 pointers. */
struct node* newNode(int data)
{
  struct node* node =
      (struct node*)malloc(sizeof(struct node));
  node->data = data;
  node->left = NULL;
  node->right = NULL;
  return(node);
}
 
/* Driver program to test above functions */
int main()
{
  struct node *root = newNode(50);
  root->left        = newNode(7);
  root->right       = newNode(2);
  root->left->left  = newNode(3);
  root->left->right = newNode(5);
  root->right->left  = newNode(1);
  root->right->right = newNode(30);
 
  printf("\n Inorder traversal before conversion ");
  printInorder(root);
 
  convertTree(root);
 
  printf("\n Inorder traversal after conversion ");
  printInorder(root);
 
  getchar();
  return 0;
}


Java
// Java program to convert an arbitrary binary tree to a tree that holds
// children sum property
  
// A binary tree node
class Node
{
    int data;
    Node left, right;
  
    Node(int item)
    {
        data = item;
        left = right = null;
    }
}
  
class BinaryTree
{
    Node root;
    /* This function changes a tree to hold children sum
       property */
  
    void convertTree(Node node)
    {
        int left_data = 0, right_data = 0, diff;
  
        /* If tree is empty or it's a leaf node then
         return true */
        if (node == null
                || (node.left == null && node.right == null))
            return;
        else
        {
            /* convert left and right subtrees  */
            convertTree(node.left);
            convertTree(node.right);
        
            /* If left child is not present then 0 is used
             as data of left child */
            if (node.left != null)
                left_data = node.left.data;
             
            /* If right child is not present then 0 is used
             as data of right child */
            if (node.right != null)
                right_data = node.right.data;
  
            /* get the diff of node's data and children sum */
            diff = left_data + right_data - node.data;
  
            /* If node's children sum is greater than the node's data */
            if (diff > 0)
                node.data = node.data + diff;
  
            /* THIS IS TRICKY --> If node's data is greater than children
               sum, then increment subtree by diff */
            if (diff < 0)
             
                // -diff is used to make diff positive
                increment(node, -diff); 
        }
    }
  
    /* This function is used to increment subtree by diff */
    void increment(Node node, int diff)
    {
        /* IF left child is not NULL then increment it */
        if (node.left != null)
        {
            node.left.data = node.left.data + diff;
  
            // Recursively call to fix the descendants of node->left
            increment(node.left, diff);
        }
        else if (node.right != null) // Else increment right child
        {
            node.right.data = node.right.data + diff;
  
            // Recursively call to fix the descendants of node->right
            increment(node.right, diff);
        }
    }
  
    /* Given a binary tree, printInorder() prints out its
     inorder traversal*/
    void printInorder(Node node)
    {
        if (node == null)
            return;
             
        /* first recur on left child */
        printInorder(node.left);
  
        /* then print the data of node */
        System.out.print(node.data + " ");
  
        /* now recur on right child */
        printInorder(node.right);
    }
  
    // Driver program to test above functions
    public static void main(String args[])
    {
        BinaryTree tree = new BinaryTree();
        tree.root = new Node(50);
        tree.root.left = new Node(7);
        tree.root.right = new Node(2);
        tree.root.left.left = new Node(3);
        tree.root.left.right = new Node(5);
        tree.root.right.left = new Node(1);
        tree.root.right.right = new Node(30);
  
        System.out.println("Inorder traversal before conversion is :");
        tree.printInorder(tree.root);
  
        tree.convertTree(tree.root);
        System.out.println("");
  
        System.out.println("Inorder traversal after conversion is :");
        tree.printInorder(tree.root);
  
    }
}
 
// This code has been contributed by Mayank Jaiswal(mayank_24)


Python3
# Program to convert an arbitrary binary tree
# to a tree that holds children sum property
 
# Helper function that allocates a new
# node with the given data and None
# left and right pointers.                                    
class newNode:
 
    # Construct to create a new node
    def __init__(self, key):
        self.data = key
        self.left = None
        self.right = None
 
# This function changes a tree to
# hold children sum property
def convertTree(node):
 
    left_data = 0
    right_data = 0
    diff=0
 
    # If tree is empty or it's a
    # leaf node then return true
    if (node == None or (node.left == None and
                         node.right == None)):
        return
     
    else:
         
        """ convert left and right subtrees """
        convertTree(node.left)
        convertTree(node.right)
 
    """ If left child is not present then 0
    is used as data of left child """
    if (node.left != None):
        left_data = node.left.data
 
    """ If right child is not present then 0
    is used as data of right child """
    if (node.right != None):
        right_data = node.right.data
 
    """ get the diff of node's data
        and children sum """
    diff = left_data + right_data - node.data
 
    """ If node's children sum is greater
        than the node's data """
    if (diff > 0):
        node.data = node.data + diff
 
    """ THIS IS TRICKY -. If node's data is
    greater than children sum, then increment
    subtree by diff """
    if (diff < 0):
        increment(node, -diff) # -diff is used to
                               # make diff positive
 
""" This function is used to increment
    subtree by diff """
def increment(node, diff):
 
    """ IF left child is not None
        then increment it """
    if(node.left != None):
        node.left.data = node.left.data + diff
 
        # Recursively call to fix the
        # descendants of node.left
        increment(node.left, diff)
 
    elif(node.right != None): # Else increment right child
        node.right.data = node.right.data + diff
 
        # Recursively call to fix the
        # descendants of node.right
        increment(node.right, diff)
 
""" Given a binary tree, printInorder()
prints out its inorder traversal"""
def printInorder(node):
 
    if (node == None):
        return
 
    """ first recur on left child """
    printInorder(node.left)
 
    """ then print the data of node """
    print(node.data,end=" ")
 
    """ now recur on right child """
    printInorder(node.right)
 
# Driver Code
if __name__ == '__main__':
    root = newNode(50)
    root.left     = newNode(7)
    root.right     = newNode(2)
    root.left.left = newNode(3)
    root.left.right = newNode(5)
    root.right.left = newNode(1)
    root.right.right = newNode(30)
 
    print("Inorder traversal before conversion")
    printInorder(root)
 
    convertTree(root)
 
    print("\nInorder traversal after conversion ")
    printInorder(root)
 
# This code is contributed by
# Shubham Singh(SHUBHAMSINGH10)


C#
// C# program to convert an arbitrary
// binary tree to a tree that holds
// children sum property
using System;
 
// A binary tree node
public class Node
{
    public int data;
    public Node left, right;
 
    public Node(int item)
    {
        data = item;
        left = right = null;
    }
}
 
class GFG
{
public Node root;
 
/* This function changes a tree to
hold children sum property */
public virtual void convertTree(Node node)
{
    int left_data = 0, right_data = 0, diff;
 
    /* If tree is empty or it's a leaf
    node then return true */
    if (node == null || (node.left == null &&
                         node.right == null))
    {
        return;
    }
    else
    {
        /* convert left and right subtrees */
        convertTree(node.left);
        convertTree(node.right);
 
        /* If left child is not present then
        0 is used as data of left child */
        if (node.left != null)
        {
            left_data = node.left.data;
        }
 
        /* If right child is not present then
        0 is used as data of right child */
        if (node.right != null)
        {
            right_data = node.right.data;
        }
 
        /* get the diff of node's data
           and children sum */
        diff = left_data + right_data - node.data;
 
        /* If node's children sum is greater
           than the node's data */
        if (diff > 0)
        {
            node.data = node.data + diff;
        }
 
        /* THIS IS TRICKY --> If node's data is
        greater than children sum, then increment
        subtree by diff */
        if (diff < 0)
        {
 
            // -diff is used to make diff positive
            increment(node, -diff);
        }
    }
}
 
/* This function is used to increment
subtree by diff */
public virtual void increment(Node node, int diff)
{
    /* IF left child is not NULL then
    increment it */
    if (node.left != null)
    {
        node.left.data = node.left.data + diff;
 
        // Recursively call to fix the
        // descendants of node->left
        increment(node.left, diff);
    }
    else if (node.right != null) // Else increment right child
    {
        node.right.data = node.right.data + diff;
 
        // Recursively call to fix the
        // descendants of node->right
        increment(node.right, diff);
    }
}
 
/* Given a binary tree, printInorder()
prints out its inorder traversal*/
public virtual void printInorder(Node node)
{
    if (node == null)
    {
        return;
    }
 
    /* first recur on left child */
    printInorder(node.left);
 
    /* then print the data of node */
    Console.Write(node.data + " ");
 
    /* now recur on right child */
    printInorder(node.right);
}
 
// Driver Code
public static void Main(string[] args)
{
    GFG tree = new GFG();
    tree.root = new Node(50);
    tree.root.left = new Node(7);
    tree.root.right = new Node(2);
    tree.root.left.left = new Node(3);
    tree.root.left.right = new Node(5);
    tree.root.right.left = new Node(1);
    tree.root.right.right = new Node(30);
 
    Console.WriteLine("Inorder traversal " +
                  "before conversion is :");
    tree.printInorder(tree.root);
 
    tree.convertTree(tree.root);
    Console.WriteLine("");
 
    Console.WriteLine("Inorder traversal " +
                   "after conversion is :");
    tree.printInorder(tree.root);
}
}
 
// This code is contributed by Shrikant13


Javascript


输出:

Inorder traversal before conversion is :
3 7 5 50 1 2 30
Inorder traversal after conversion is :
14 19 5 50 1 31 30

时间复杂度: O(n^2),最坏情况下的复杂度是一棵倾斜的树,使得节点从根到叶按降序排列。