Monday, November 18, 2024
Google search engine
HomeData Modelling & AIFind the largest Complete Subtree in a given Binary Tree

Find the largest Complete Subtree in a given Binary Tree

Given a Binary Tree, the task is to find the size of largest Complete sub-tree in the given Binary Tree. 
Complete Binary Tree – A Binary tree is Complete Binary Tree if all levels are completely filled except possibly the last level and the last level has all keys as left as possible.

Note: All Perfect Binary Trees are Complete Binary tree but reverse in NOT true. If a tree is not complete then it is also not Perfect Binary Tree. 

Examples: 

Input: 
              1
           /     \
          2        3
        /   \     /  \
       4      5   6   7  
     /  \    /        
    8   9   10      
Output:
Size : 10
Inorder Traversal : 8 4 9 2 10 5 1 6 3 7
The given tree a complete binary tree.

Input:
         50
      /      \
   30         60
  /   \      /    \ 
 5    20   45      70
          / 
         10
Output:
Size : 4
Inorder Traversal : 10 45 60 70

Approach: Simply traverse the tree in bottom up manner. Then on coming up in recursion from child to parent, we can pass information about sub-trees to the parent. The passed information can be used by the parent to do Complete Tree test (for parent node) only in constant time. Both left and right sub-trees need to tell the parent information whether they are perfect or not and complete or not and they also need to return the max size of complete binary tree found till now. 

The sub-trees need to pass the following information up the tree for finding the largest Complete sub-tree so that we can compare the maximum size with the parent’s data to check the Complete Binary Tree property. 

  1. There is a bool variable to check whether the left child or the right child sub-tree is Perfect and Complete or not.
  2. From left and right child calls in recursion we find out if parent sub-tree is Complete or not by following 3 cases: 
    • If left subtree is perfect and right is complete and there height is also same then sub-tree root is also complete binary subtree with size equal to sum of left and right subtrees plus one (for current root).
    • If left subtree is complete and right is perfect and the height of left is greater than right by one then sub-tree root is complete binary subtree with size equal to sum of left and right subtrees plus one (for current root). And root subtree cannot be perfect binary subtree because in this case its left child is not perfect.
    • Else this sub-tree cannot be a complete binary tree and simply return the biggest sized complete sub-tree found till now in the left or right sub-trees.And if tree is not complete then it is not perfect also.

Below is the implementation of the above approach: 

C++




// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
 
// Node structure of the tree
struct node {
    int data;
    struct node* left;
    struct node* right;
};
 
// To create a new node
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;
};
 
// Structure for return type of
// function findPerfectBinaryTree
struct returnType {
 
    // To store if sub-tree is perfect or not
    bool isPerfect;
 
    // To store if sub-tree is complete or not
    bool isComplete;
 
    // size of the tree
    int size;
 
    // Root of biggest complete sub-tree
    node* rootTree;
};
 
// helper function that returns height
// of the tree given size
int getHeight(int size)
{
    return ceil(log2(size + 1));
}
 
// Function to return the biggest
// complete binary sub-tree
returnType findCompleteBinaryTree(struct node* root)
{
 
    // Declaring returnType that
    // needs to be returned
    returnType rt;
 
    // If root is NULL then it is considered as both
    // perfect and complete binary tree of size 0
    if (root == NULL) {
        rt.isPerfect = true;
        rt.isComplete = true;
        rt.size = 0;
        rt.rootTree = NULL;
        return rt;
    }
 
    // Recursive call for left and right child
    returnType lv = findCompleteBinaryTree(root->left);
    returnType rv = findCompleteBinaryTree(root->right);
 
    // CASE - A
    // If left sub-tree is perfect and right is complete and
    // there height is also same then sub-tree root
    // is also complete binary sub-tree with size equal to
    // sum of left and right subtrees plus one for current root
    if (lv.isPerfect == true && rv.isComplete == true
        && getHeight(lv.size) == getHeight(rv.size)) {
        rt.isComplete = true;
 
        // If right sub-tree is perfect then
        // root is also perfect
        rt.isPerfect = (rv.isPerfect ? true : false);
        rt.size = lv.size + rv.size + 1;
        rt.rootTree = root;
        return rt;
    }
 
    // CASE - B
    // If left sub-tree is complete and right is perfect and the
    // height of left is greater than right by one then sub-tree root
    // is complete binary sub-tree with size equal to
    // sum of left and right subtrees plus one for current root.
    // But sub-tree cannot be perfect binary sub-tree.
    if (lv.isComplete == true && rv.isPerfect == true
        && getHeight(lv.size) == getHeight(rv.size) + 1) {
        rt.isComplete = true;
        rt.isPerfect = false;
        rt.size = lv.size + rv.size + 1;
        rt.rootTree = root;
        return rt;
    }
 
    // CASE - C
    // Else this sub-tree cannot be a complete binary tree
    // and simply return the biggest sized complete sub-tree
    // found till now in the left or right sub-trees
    rt.isPerfect = false;
    rt.isComplete = false;
    rt.size = max(lv.size, rv.size);
    rt.rootTree = (lv.size > rv.size ? lv.rootTree : rv.rootTree);
    return rt;
}
 
// Function to print the inorder traversal of the tree
void inorderPrint(node* root)
{
    if (root != NULL) {
        inorderPrint(root->left);
        cout << root->data << " ";
        inorderPrint(root->right);
    }
}
 
// Driver code
int main()
{
    // Create the tree
    struct node* root = newNode(50);
    root->left = newNode(30);
    root->right = newNode(60);
    root->left->left = newNode(5);
    root->left->right = newNode(20);
    root->right->left = newNode(45);
    root->right->right = newNode(70);
    root->right->left->left = newNode(10);
 
    // Get the biggest sized complete binary sub-tree
    struct returnType ans = findCompleteBinaryTree(root);
 
    cout << "Size : " << ans.size << endl;
 
    // Print the inorder traversal of the found sub-tree
    cout << "Inorder Traversal : ";
    inorderPrint(ans.rootTree);
 
    return 0;
}


Java




// Java implementation of the approach
class Sol
{
 
// Node structure of the tree
static class node
{
    int data;
    node left;
    node right;
};
 
// To create a new node
static node newNode(int data)
{
    node node = new node();
    node.data = data;
    node.left = null;
    node.right = null;
    return node;
};
 
// Structure for return type of
// function findPerfectBinaryTree
static class returnType
{
 
    // To store if sub-tree is perfect or not
    boolean isPerfect;
 
    // To store if sub-tree is complete or not
    boolean isComplete;
 
    // size of the tree
    int size;
 
    // Root of biggest complete sub-tree
    node rootTree;
};
 
// helper function that returns height
// of the tree given size
static int getHeight(int size)
{
    return (int)Math.ceil(Math.log(size + 1)/Math.log(2));
}
 
// Function to return the biggest
// complete binary sub-tree
static returnType findCompleteBinaryTree(node root)
{
 
    // Declaring returnType that
    // needs to be returned
    returnType rt=new returnType();
 
    // If root is null then it is considered as both
    // perfect and complete binary tree of size 0
    if (root == null)
    {
        rt.isPerfect = true;
        rt.isComplete = true;
        rt.size = 0;
        rt.rootTree = null;
        return rt;
    }
 
    // Recursive call for left and right child
    returnType lv = findCompleteBinaryTree(root.left);
    returnType rv = findCompleteBinaryTree(root.right);
 
    // CASE - A
    // If left sub-tree is perfect and right is complete and
    // there height is also same then sub-tree root
    // is also complete binary sub-tree with size equal to
    // sum of left and right subtrees plus one for current root
    if (lv.isPerfect == true && rv.isComplete == true
        && getHeight(lv.size) == getHeight(rv.size))
    {
        rt.isComplete = true;
 
        // If right sub-tree is perfect then
        // root is also perfect
        rt.isPerfect = (rv.isPerfect ? true : false);
        rt.size = lv.size + rv.size + 1;
        rt.rootTree = root;
        return rt;
    }
 
    // CASE - B
    // If left sub-tree is complete and right is perfect and the
    // height of left is greater than right by one then sub-tree root
    // is complete binary sub-tree with size equal to
    // sum of left and right subtrees plus one for current root.
    // But sub-tree cannot be perfect binary sub-tree.
    if (lv.isComplete == true && rv.isPerfect == true
        && getHeight(lv.size) == getHeight(rv.size) + 1)
    {
        rt.isComplete = true;
        rt.isPerfect = false;
        rt.size = lv.size + rv.size + 1;
        rt.rootTree = root;
        return rt;
    }
 
    // CASE - C
    // Else this sub-tree cannot be a complete binary tree
    // and simply return the biggest sized complete sub-tree
    // found till now in the left or right sub-trees
    rt.isPerfect = false;
    rt.isComplete = false;
    rt.size = Math.max(lv.size, rv.size);
    rt.rootTree = (lv.size > rv.size ? lv.rootTree : rv.rootTree);
    return rt;
}
 
// Function to print the inorder traversal of the tree
static void inorderPrint(node root)
{
    if (root != null)
    {
        inorderPrint(root.left);
        System.out.print( root.data + " ");
        inorderPrint(root.right);
    }
}
 
// Driver code
public static void main(String args[])
{
    // Create the tree
    node root = newNode(50);
    root.left = newNode(30);
    root.right = newNode(60);
    root.left.left = newNode(5);
    root.left.right = newNode(20);
    root.right.left = newNode(45);
    root.right.right = newNode(70);
    root.right.left.left = newNode(10);
 
    // Get the biggest sized complete binary sub-tree
    returnType ans = findCompleteBinaryTree(root);
 
    System.out.println( "Size : " + ans.size );
 
    // Print the inorder traversal of the found sub-tree
    System.out.print("Inorder Traversal : ");
    inorderPrint(ans.rootTree);
 
}
}
 
// This code is contributed by Arnab Kundu


Python3




# Python3 implementation of the approach
import math
 
# Node structure of the tree
class node :
    def __init__(self):
        self.data = 0
        self.left = None
        self.right = None
 
# To create a new node
def newNode(data):
 
    node_ = node()
    node_.data = data
    node_.left = None
    node_.right = None
    return node_
 
# Structure for return type of
# function findPerfectBinaryTree
class returnType :
 
    def __init__(self):
 
        # To store if sub-tree is perfect or not
        self.isPerfect = None
 
        # To store if sub-tree is complete or not
        self.isComplete = None
 
        # size of the tree
        self.size = 0
 
        # Root of biggest complete sub-tree
        self.rootTree = None
 
# helper function that returns height
# of the tree given size
def getHeight(size):
 
    return int(math.ceil(math.log(size + 1)/math.log(2)))
 
# Function to return the biggest
# complete binary sub-tree
def findCompleteBinaryTree(root) :
 
 
    # Declaring returnType that
    # needs to be returned
    rt = returnType()
 
    # If root is None then it is considered as both
    # perfect and complete binary tree of size 0
    if (root == None):
     
        rt.isPerfect = True
        rt.isComplete = True
        rt.size = 0
        rt.rootTree = None
        return rt
     
 
    # Recursive call for left and right child
    lv = findCompleteBinaryTree(root.left)
    rv = findCompleteBinaryTree(root.right)
 
    # CASE - A
    # If left sub-tree is perfect and right is complete and
    # there height is also same then sub-tree root
    # is also complete binary sub-tree with size equal to
    # sum of left and right subtrees plus one for current root
    if (lv.isPerfect == True and rv.isComplete == True
        and getHeight(lv.size) == getHeight(rv.size)) :
     
        rt.isComplete = True
 
        # If right sub-tree is perfect then
        # root is also perfect
        rt.isPerfect = rv.isPerfect
        rt.size = lv.size + rv.size + 1
        rt.rootTree = root
        return rt
     
    # CASE - B
    # If left sub-tree is complete and right is perfect and the
    # height of left is greater than right by one then sub-tree root
    # is complete binary sub-tree with size equal to
    # sum of left and right subtrees plus one for current root.
    # But sub-tree cannot be perfect binary sub-tree.
    if (lv.isComplete == True and rv.isPerfect == True
        and getHeight(lv.size) == getHeight(rv.size) + 1):
     
        rt.isComplete = True
        rt.isPerfect = False
        rt.size = lv.size + rv.size + 1
        rt.rootTree = root
        return rt
     
    # CASE - C
    # Else this sub-tree cannot be a complete binary tree
    # and simply return the biggest sized complete sub-tree
    # found till now in the left or right sub-trees
    rt.isPerfect = False
    rt.isComplete = False
    rt.size =max(lv.size, rv.size)
    if(lv.size > rv.size ):
        rt.rootTree = lv.rootTree
    else:
        rt.rootTree = rv.rootTree
    return rt
 
# Function to print the inorder traversal of the tree
def inorderPrint(root) :
 
    if (root != None) :
     
        inorderPrint(root.left)
        print( root.data ,end= " ")
        inorderPrint(root.right)
     
# Driver code
 
# Create the tree
root = newNode(50)
root.left = newNode(30)
root.right = newNode(60)
root.left.left = newNode(5)
root.left.right = newNode(20)
root.right.left = newNode(45)
root.right.right = newNode(70)
root.right.left.left = newNode(10)
 
# Get the biggest sized complete binary sub-tree
ans = findCompleteBinaryTree(root)
 
print( "Size : " , ans.size )
 
# Print the inorder traversal of the found sub-tree
print("Inorder Traversal : ")
inorderPrint(ans.rootTree)
 
# This code is contributed by Arnab Kundu


C#




// C# implementation of the above approach:
using System;
 
class GFG
{
 
// Node structure of the tree
public class node
{
    public int data;
    public node left;
    public node right;
};
 
// To create a new node
static node newNode(int data)
{
    node node = new node();
    node.data = data;
    node.left = null;
    node.right = null;
    return node;
}
 
// Structure for return type of
// function findPerfectBinaryTree
public class returnType
{
 
    // To store if sub-tree is perfect or not
    public Boolean isPerfect;
 
    // To store if sub-tree is complete or not
    public Boolean isComplete;
 
    // size of the tree
    public int size;
 
    // Root of biggest complete sub-tree
    public node rootTree;
};
 
// helper function that returns height
// of the tree given size
static int getHeight(int size)
{
    return (int)Math.Ceiling(Math.Log(size + 1) /
                             Math.Log(2));
}
 
// Function to return the biggest
// complete binary sub-tree
static returnType findCompleteBinaryTree(node root)
{
 
    // Declaring returnType that
    // needs to be returned
    returnType rt=new returnType();
 
    // If root is null then it is considered
    // as both perfect and complete binary
    // tree of size 0
    if (root == null)
    {
        rt.isPerfect = true;
        rt.isComplete = true;
        rt.size = 0;
        rt.rootTree = null;
        return rt;
    }
 
    // Recursive call for left and right child
    returnType lv = findCompleteBinaryTree(root.left);
    returnType rv = findCompleteBinaryTree(root.right);
 
    // CASE - A
    // If left sub-tree is perfect and right is
    // complete and there height is also same
    // then sub-tree root is also complete binary
    // sub-tree with size equal to sum of left
    // and right subtrees plus one for current root
    if (lv.isPerfect == true &&
        rv.isComplete == true &&
        getHeight(lv.size) == getHeight(rv.size))
    {
        rt.isComplete = true;
 
        // If right sub-tree is perfect then
        // root is also perfect
        rt.isPerfect = (rv.isPerfect ? true : false);
        rt.size = lv.size + rv.size + 1;
        rt.rootTree = root;
        return rt;
    }
 
    // CASE - B
    // If left sub-tree is complete and right is
    // perfect and the height of left is greater than
    // right by one then sub-tree root is complete
    // binary sub-tree with size equal to
    // sum of left and right subtrees plus one
    // for current root. But sub-tree cannot be
    // perfect binary sub-tree.
    if (lv.isComplete == true &&
        rv.isPerfect == true &&
        getHeight(lv.size) == getHeight(rv.size) + 1)
    {
        rt.isComplete = true;
        rt.isPerfect = false;
        rt.size = lv.size + rv.size + 1;
        rt.rootTree = root;
        return rt;
    }
 
    // CASE - C
    // Else this sub-tree cannot be a complete
    // binary tree and simply return the biggest
    // sized complete sub-tree found till now
    // in the left or right sub-trees
    rt.isPerfect = false;
    rt.isComplete = false;
    rt.size = Math.Max(lv.size, rv.size);
    rt.rootTree = (lv.size > rv.size ?
                         lv.rootTree : rv.rootTree);
    return rt;
}
 
// Function to print the
// inorder traversal of the tree
static void inorderPrint(node root)
{
    if (root != null)
    {
        inorderPrint(root.left);
        Console.Write(root.data + " ");
        inorderPrint(root.right);
    }
}
 
// Driver code
public static void Main(String []args)
{
    // Create the tree
    node root = newNode(50);
    root.left = newNode(30);
    root.right = newNode(60);
    root.left.left = newNode(5);
    root.left.right = newNode(20);
    root.right.left = newNode(45);
    root.right.right = newNode(70);
    root.right.left.left = newNode(10);
 
    // Get the biggest sized complete binary sub-tree
    returnType ans = findCompleteBinaryTree(root);
 
    Console.WriteLine("Size : " + ans.size);
 
    // Print the inorder traversal
    // of the found sub-tree
    Console.Write("Inorder Traversal : ");
    inorderPrint(ans.rootTree);
}
}
 
// This code is contributed by PrinciRaj1992


Javascript




<script>
 
// Javascript implementation of the approach
 
// Node structure of the tree
class node
{
    constructor(data)
    {
        this.left = null;
        this.right = null;
        this.data = data;
    }
}
 
// To create a new node
function newNode(data)
{
    let Node = new node(data);
    return Node;
}
 
// Structure for return type of
// function findPerfectBinaryTree
class returnType
{
    constructor()
    {
         
        // To store if sub-tree is perfect or not
        this.isPerfect;
         
        // To store if sub-tree is complete or not
        this.isComplete;
         
        // size of the tree
        this.size;
         
        // Root of biggest complete sub-tree
        this.rootTree;
    }
}
 
// Helper function that returns height
// of the tree given size
function getHeight(size)
{
    return Math.ceil(Math.log(size + 1) /
                     Math.log(2));
}
 
// Function to return the biggest
// complete binary sub-tree
function findCompleteBinaryTree(root)
{
     
    // Declaring returnType that
    // needs to be returned
    let rt = new returnType();
     
    // If root is null then it is considered as both
    // perfect and complete binary tree of size 0
    if (root == null)
    {
        rt.isPerfect = true;
        rt.isComplete = true;
        rt.size = 0;
        rt.rootTree = null;
        return rt;
    }
     
    // Recursive call for left and right child
    let lv = findCompleteBinaryTree(root.left);
    let rv = findCompleteBinaryTree(root.right);
     
    // CASE - A
    // If left sub-tree is perfect and right is
    // complete and there height is also same
    // then sub-tree root is also complete
    // binary sub-tree with size equal to
    // sum of left and right subtrees plus
    // one for current root
    if (lv.isPerfect == true && rv.isComplete == true &&
        getHeight(lv.size) == getHeight(rv.size))
    {
        rt.isComplete = true;
         
        // If right sub-tree is perfect then
        // root is also perfect
        rt.isPerfect = (rv.isPerfect ? true : false);
        rt.size = lv.size + rv.size + 1;
        rt.rootTree = root;
        return rt;
    }
     
    // CASE - B
    // If left sub-tree is complete and right
    // is perfect and the height of left is
    // greater than right by one then sub-tree root
    // is complete binary sub-tree with size equal to
    // sum of left and right subtrees plus one for
    // current root. But sub-tree cannot be perfect
    // binary sub-tree.
    if (lv.isComplete == true && rv.isPerfect == true &&
        getHeight(lv.size) == getHeight(rv.size) + 1)
    {
        rt.isComplete = true;
        rt.isPerfect = false;
        rt.size = lv.size + rv.size + 1;
        rt.rootTree = root;
        return rt;
    }
     
    // CASE - C
    // Else this sub-tree cannot be a complete
    // binary tree and simply return the biggest
    // sized complete sub-tree found till now in
    // the left or right sub-trees
    rt.isPerfect = false;
    rt.isComplete = false;
    rt.size = Math.max(lv.size, rv.size);
    rt.rootTree = (lv.size > rv.size ?
                   lv.rootTree : rv.rootTree);
    return rt;
}
 
// Function to print the inorder
// traversal of the tree
function inorderPrint(root)
{
    if (root != null)
    {
        inorderPrint(root.left);
        document.write(root.data + " ");
        inorderPrint(root.right);
    }
}
 
// Driver code
 
// Create the tree
let root = newNode(50);
root.left = newNode(30);
root.right = newNode(60);
root.left.left = newNode(5);
root.left.right = newNode(20);
root.right.left = newNode(45);
root.right.right = newNode(70);
root.right.left.left = newNode(10);
 
// Get the biggest sized complete binary sub-tree
let ans = findCompleteBinaryTree(root);
 
document.write( "Size : " + ans.size + "</br>");
 
// Print the inorder traversal of the found sub-tree
document.write("Inorder Traversal : ");
inorderPrint(ans.rootTree);
 
// This code is contributed by suresh07
 
</script>


Output: 

Size : 4
Inorder Traversal : 10 45 60 70

 

Time Complexity: O(N), where N is the total number of nodes present in the tree.

Space Complexity: O(N). The size of the stack used for recursion is the same order as the size of the tree

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

RELATED ARTICLES

Most Popular

Recent Comments