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++
// 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> |
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
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!