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++

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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

chevron_right


Output:

Size : 4
Inorder Traversal : 10 45 60 70


My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



Improved By : andrew1234



Article Tags :
Practice Tags :


2


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.