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.
- There is a bool variable to check whether the left child or the right child sub-tree is Perfect and Complete or not.
- 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++ 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 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 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# 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 |
<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> |
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