Check whether a given binary tree is perfect or not
Last Updated :
23 Nov, 2023
Given a Binary Tree, write a function to check whether the given Binary Tree is a perfect Binary Tree or not.
A Binary tree is Perfect Binary Tree in which all internal nodes have two children and all leaves are at same level.
Examples:
The following tree is a perfect binary tree
10
/ \
20 30
/ \ / \
40 50 60 70
18
/ \
15 30
The following tree is not a perfect binary tree
1
/ \
2 3
\ / \
4 5 6
A Perfect Binary Tree of height h (where height is number of nodes on path from root to leaf) has 2h – 1 nodes.
Solution Approach:
Method 1:
- Find depth of any node (in below tree we find depth of leftmost node). Let this depth be d.
- Now recursively traverse the tree and check for following two conditions.
- Every internal node should have both children non-empty
- All leaves are at depth ‘d’
Below is the implementation:
C++
#include<bits/stdc++.h>
struct Node
{
int key;
struct Node *left, *right;
};
int findADepth(Node *node)
{
int d = 0;
while (node != NULL)
{
d++;
node = node->left;
}
return d;
}
bool isPerfectRec( struct Node* root, int d, int level = 0)
{
if (root == NULL)
return true ;
if (root->left == NULL && root->right == NULL)
return (d == level+1);
if (root->left == NULL || root->right == NULL)
return false ;
return isPerfectRec(root->left, d, level+1) &&
isPerfectRec(root->right, d, level+1);
}
bool isPerfect(Node *root)
{
int d = findADepth(root);
return isPerfectRec(root, d);
}
struct Node *newNode( int k)
{
struct Node *node = new Node;
node->key = k;
node->right = node->left = NULL;
return node;
}
int main()
{
struct Node* root = NULL;
root = newNode(10);
root->left = newNode(20);
root->right = newNode(30);
root->left->left = newNode(40);
root->left->right = newNode(50);
root->right->left = newNode(60);
root->right->right = newNode(70);
if (isPerfect(root))
printf ( "Yes\n" );
else
printf ( "No\n" );
return (0);
}
|
Java
class GfG {
static class Node
{
int key;
Node left, right;
}
static int findADepth(Node node)
{
int d = 0 ;
while (node != null )
{
d++;
node = node.left;
}
return d;
}
static boolean isPerfectRec(Node root, int d, int level)
{
if (root == null )
return true ;
if (root.left == null && root.right == null )
return (d == level+ 1 );
if (root.left == null || root.right == null )
return false ;
return isPerfectRec(root.left, d, level+ 1 ) && isPerfectRec(root.right, d, level+ 1 );
}
static boolean isPerfect(Node root)
{
int d = findADepth(root);
return isPerfectRec(root, d, 0 );
}
static Node newNode( int k)
{
Node node = new Node();
node.key = k;
node.right = null ;
node.left = null ;
return node;
}
public static void main(String args[])
{
Node root = null ;
root = newNode( 10 );
root.left = newNode( 20 );
root.right = newNode( 30 );
root.left.left = newNode( 40 );
root.left.right = newNode( 50 );
root.right.left = newNode( 60 );
root.right.right = newNode( 70 );
if (isPerfect(root) == true )
System.out.println( "Yes" );
else
System.out.println( "No" );
}
}
|
Python3
class newNode:
def __init__( self , k):
self .key = k
self .right = self .left = None
def findADepth(node):
d = 0
while (node ! = None ):
d + = 1
node = node.left
return d
def isPerfectRec(root, d, level = 0 ):
if (root = = None ):
return True
if (root.left = = None and root.right = = None ):
return (d = = level + 1 )
if (root.left = = None or root.right = = None ):
return False
return (isPerfectRec(root.left, d, level + 1 ) and
isPerfectRec(root.right, d, level + 1 ))
def isPerfect(root):
d = findADepth(root)
return isPerfectRec(root, d)
if __name__ = = '__main__' :
root = None
root = newNode( 10 )
root.left = newNode( 20 )
root.right = newNode( 30 )
root.left.left = newNode( 40 )
root.left.right = newNode( 50 )
root.right.left = newNode( 60 )
root.right.right = newNode( 70 )
if (isPerfect(root)):
print ( "Yes" )
else :
print ( "No" )
|
C#
using System;
class GfG
{
class Node
{
public int key;
public Node left, right;
}
static int findADepth(Node node)
{
int d = 0;
while (node != null )
{
d++;
node = node.left;
}
return d;
}
static bool isPerfectRec(Node root,
int d, int level)
{
if (root == null )
return true ;
if (root.left == null && root.right == null )
return (d == level+1);
if (root.left == null || root.right == null )
return false ;
return isPerfectRec(root.left, d, level+1) &&
isPerfectRec(root.right, d, level+1);
}
static bool isPerfect(Node root)
{
int d = findADepth(root);
return isPerfectRec(root, d, 0);
}
static Node newNode( int k)
{
Node node = new Node();
node.key = k;
node.right = null ;
node.left = null ;
return node;
}
public static void Main()
{
Node root = null ;
root = newNode(10);
root.left = newNode(20);
root.right = newNode(30);
root.left.left = newNode(40);
root.left.right = newNode(50);
root.right.left = newNode(60);
root.right.right = newNode(70);
if (isPerfect(root) == true )
Console.WriteLine( "Yes" );
else
Console.WriteLine( "No" );
}
}
|
Javascript
<script>
class Node
{
constructor()
{
this .key = 0;
this .left = null ;
this .right = null ;
}
}
function findADepth(node)
{
var d = 0;
while (node != null )
{
d++;
node = node.left;
}
return d;
}
function isPerfectRec(root, d, level)
{
if (root == null )
return true ;
if (root.left == null && root.right == null )
return (d == level + 1);
if (root.left == null || root.right == null )
return false ;
return isPerfectRec(root.left, d, level + 1) &&
isPerfectRec(root.right, d, level + 1);
}
function isPerfect(root)
{
var d = findADepth(root);
return isPerfectRec(root, d, 0);
}
function newNode(k)
{
var node = new Node();
node.key = k;
node.right = null ;
node.left = null ;
return node;
}
var root = null ;
root = newNode(10);
root.left = newNode(20);
root.right = newNode(30);
root.left.left = newNode(40);
root.left.right = newNode(50);
root.right.left = newNode(60);
root.right.right = newNode(70);
if (isPerfect(root) == true )
document.write( "Yes" );
else
document.write( "No" );
</script>
|
Complexity Analysis:
- Time complexity: O(n)
- Space Complexity: O(n)
Method 2: Using Recursion
Since a full binary tree has 2^h – 1 nodes, we can count the number of nodes in the binary tree and determine whether it is a power of 2 or not. Also, the number of nodes (n) should be equal to 2^h – 1.
//Flow of recursion
1. if either left or right child is missing, tree is imperfect return false.
2. If both children are missing (leaf node), return true.
3. if either the left/right children of the left subtree or the left/right children of the right subtree is missing , means leaves aren’t at same level so tree is imperfect hence return false.
3. If either left or right subtree is not perfect, return false.
4. else If all conditions pass, the tree is perfect.
Below is the implementation:
C++
#include <iostream>
class Node {
public :
int data;
Node* left;
Node* right;
Node( int data) {
this ->data = data;
this ->left = this ->right = nullptr;
}
};
bool isPerfect(Node* root) {
if ((root->left == nullptr) != (root->right == nullptr))
return false ;
if (root->left == nullptr)
return true ;
if ((root->left->left == nullptr) != (root->right->left == nullptr))
return false ;
if (!isPerfect(root->left) || !isPerfect(root->right))
return false ;
return true ;
}
int main() {
Node* root = new Node(10);
root->left = new Node(20);
root->right = new Node(30);
root->left->left = new Node(40);
root->left->right = new Node(50);
root->right->left = new Node(60);
root->right->right = new Node(70);
bool isPerfectTree = isPerfect(root);
if (isPerfectTree) {
std::cout << "The binary tree is perfect." << std::endl;
} else {
std::cout << "The binary tree is not perfect." << std::endl;
}
return 0;
}
|
Java
import java.io.*;
class Node {
int data;
Node left, right;
public Node( int data)
{
this .data = data;
this .left = this .right = null ;
}
}
public class GFG {
public static boolean isPerfect(Node root)
{
if (root.left == null ^ root.right == null )
return false ;
if (root.left == null )
return true ;
if (root.left.left == null
^ root.right.left == null )
return false ;
if (!isPerfect(root.left) || !isPerfect(root.right))
return false ;
else
return true ;
}
public static void main(String[] args)
{
Node root = new Node( 10 );
root.left = new Node( 20 );
root.right = new Node( 30 );
root.left.left = new Node( 40 );
root.left.right = new Node( 50 );
root.right.left = new Node( 60 );
root.right.right = new Node( 70 );
boolean isPerfectTree = isPerfect(root);
if (isPerfectTree) {
System.out.println(
"The binary tree is perfect." );
}
else {
System.out.println(
"The binary tree is not perfect." );
}
}
}
|
Python3
class Node:
def __init__( self , data):
self .data = data
self .left = None
self .right = None
def isPerfect(root):
if (root.left is None ) ! = (root.right is None ):
return False
if root.left is None :
return True
if (root.left.left is None ) ! = (root.right.left is None ):
return False
if not isPerfect(root.left) or not isPerfect(root.right):
return False
return True
root = Node( 10 )
root.left = Node( 20 )
root.right = Node( 30 )
root.left.left = Node( 40 )
root.left.right = Node( 50 )
root.right.left = Node( 60 )
root.right.right = Node( 70 )
isPerfectTree = isPerfect(root)
if isPerfectTree:
print ( "The binary tree is perfect." )
else :
print ( "The binary tree is not perfect." )
|
C#
using System;
class Node
{
public int data;
public Node left;
public Node right;
public Node( int data)
{
this .data = data;
this .left = this .right = null ;
}
}
class Program
{
static bool IsPerfect(Node root)
{
if ((root.left == null ) != (root.right == null ))
return false ;
if (root.left == null )
return true ;
if ((root.left.left == null ) != (root.right.left == null ))
return false ;
if (!IsPerfect(root.left) || !IsPerfect(root.right))
return false ;
return true ;
}
static void Main( string [] args)
{
Node root = new Node(10);
root.left = new Node(20);
root.right = new Node(30);
root.left.left = new Node(40);
root.left.right = new Node(50);
root.right.left = new Node(60);
root.right.right = new Node(70);
bool isPerfectTree = IsPerfect(root);
if (isPerfectTree)
{
Console.WriteLine( "The binary tree is perfect." );
}
else
{
Console.WriteLine( "The binary tree is not perfect." );
}
}
}
|
Javascript
class Node {
constructor(data) {
this .data = data;
this .left = null ;
this .right = null ;
}
}
function isPerfect(root) {
if ((root.left === null ) !== (root.right === null ))
return false ;
if (root.left === null )
return true ;
if ((root.left.left === null ) !== (root.right.left === null ))
return false ;
if (!isPerfect(root.left) || !isPerfect(root.right))
return false ;
return true ;
}
const root = new Node(10);
root.left = new Node(20);
root.right = new Node(30);
root.left.left = new Node(40);
root.left.right = new Node(50);
root.right.left = new Node(60);
root.right.right = new Node(70);
const isPerfectTree = isPerfect(root);
if (isPerfectTree) {
console.log( "The binary tree is perfect." );
} else {
console.log( "The binary tree is not perfect." );
}
|
Output
The binary tree is perfect.
Complexity Analysis:
- Time complexity: O(n) , because each node is traversed only once
- Space Complexity: O(n) , because of recursion stack
Method 3: Using the length of the binary tree
Since a full binary tree has 2^h – 1 nodes, we can count the number of nodes in the binary tree and determine whether it is a power of 2 or not. Also, the number of nodes (n) should be equal to 2^h – 1.
Below is the implementation:
C++
#include <bits/stdc++.h>
using namespace std;
class newNode{
public :
int key;
newNode*right,*left;
newNode( int k){
this ->key = k;
this ->right = this ->left = NULL;
}
};
int getLength(newNode* root){
if (root == NULL)
return 0;
return 1 + getLength(root->left) + getLength(root->right);
}
bool isPerfect(newNode* root){
int length = getLength(root);
return (length & (length+1)) == 0;
}
int main()
{
newNode* root = new newNode(10);
root->left = new newNode(20);
root->right = new newNode(30);
root->left->left = new newNode(40);
root->left->right = new newNode(50);
root->right->left = new newNode(60);
root->right->right = new newNode(70);
if (isPerfect(root))
cout<< "Yes" <<endl;
else
cout<< "No" <<endl;
}
|
Java
import java.io.*;
class GFG
{
static class newNode{
public int key;
public newNode right,left;
public newNode( int k){
this .key = k;
this .right = this .left = null ;
}
};
static int getHeight(newNode root) {
if (root == null ) return 0 ;
else if (root.left == null && root.right == null ) return 1 ;
int lHeight = height(root.left);
int rHeight = height(root.right);
return 1 + Math.max(lHeight, rHeight);
}
static int getLength(newNode root){
if (root == null )
return 0 ;
return 1 + getLength(root.left) + getLength(root.right);
}
static boolean isPerfect(newNode root){
int length = getLength(root);
int height = getHeight(root);
return length + 1 == ( int )Math.pow( 2 , height);
}
public static void main(String args[])
{
newNode root = new newNode( 10 );
root.left = new newNode( 20 );
root.right = new newNode( 30 );
root.left.left = new newNode( 40 );
root.left.right = new newNode( 50 );
root.right.left = new newNode( 60 );
root.right.right = new newNode( 70 );
if (isPerfect(root))
System.out.println( "Yes" );
else
System.out.println( "No" );
}
}
|
Python3
class newNode:
def __init__( self , k):
self .key = k
self .right = self .left = None
def getLength(root):
if root = = None :
return 0
return 1 + getLength(root.left) + getLength(root.right)
def isPerfect(root):
length = getLength(root)
return length & (length + 1 ) = = 0
if __name__ = = '__main__' :
root = None
root = newNode( 10 )
root.left = newNode( 20 )
root.right = newNode( 30 )
root.left.left = newNode( 40 )
root.left.right = newNode( 50 )
root.right.left = newNode( 60 )
root.right.right = newNode( 70 )
if (isPerfect(root)):
print ( "Yes" )
else :
print ( "No" )
|
C#
using System;
class GfG{
class newNode
{
public int key;
public newNode left, right;
public newNode( int k){
key = k;
right = left = null ;
}
}
static int getLength(newNode root){
if (root == null ) return 0;
return 1 + getLength(root.left) + getLength(root.right);
}
static bool isPerfect(newNode root){
int length = getLength(root);
return (length & (length+1)) == 0;
}
public static void Main(){
newNode root = null ;
root = new newNode(10);
root.left = new newNode(20);
root.right = new newNode(30);
root.left.left = new newNode(40);
root.left.right = new newNode(50);
root.right.left = new newNode(60);
root.right.left.left = new newNode(70);
if (isPerfect(root) == true )
Console.WriteLine( "Yes" );
else
Console.WriteLine( "No" );
}
}
|
Javascript
<script>
class newNode{
constructor(k){
this .key = k
this .right = this .left = null
}
}
function getLength(root){
if (root == null )
return 0
return 1 + getLength(root.left) + getLength(root.right)
}
function isPerfect(root){
let length = getLength(root)
return length & (length+1) == 0
}
let root = null
root = new newNode(10)
root.left = new newNode(20)
root.right = new newNode(30)
root.left.left = new newNode(40)
root.left.right = new newNode(50)
root.right.left = new newNode(60)
root.right.right = new newNode(70)
if (isPerfect(root))
document.write( "Yes" )
else
document.write( "No" )
</script>
|
Complexity Analysis:
- Time Complexity: O(n)
- Space Complexity:O(n)
Method 4: Using level order traversal:
The idea is to perform a level-order traversal of the binary tree using a queue. By traversing the tree level by level, we can check if the tree satisfies the conditions of a perfect binary tree.
Below is the implementation:
C++
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
struct Node {
int data;
Node* left;
Node* right;
};
bool isPerfectBinaryTree(Node* root)
{
if (root == nullptr) {
return true ;
}
queue<Node*> q;
q.push(root);
int level = 1;
int flag
= 1;
while (!q.empty()) {
int size = q.size();
vector< int > levelValues;
for ( int i = 0; i < size; i++) {
Node* temp = q.front();
q.pop();
levelValues.push_back(temp->data);
if (temp->left) {
q.push(temp->left);
}
if (temp->right) {
q.push(temp->right);
}
}
if (levelValues.size() != 0
&& levelValues.size() != level) {
flag = 0;
}
level = level * 2;
}
return flag;
}
Node* createNode( int data)
{
Node* newNode = new Node();
if (newNode) {
newNode->data = data;
newNode->left = newNode->right = nullptr;
}
return newNode;
}
int main()
{
Node* root = createNode(7);
root->left = createNode(4);
root->right = createNode(9);
bool isPerfect = isPerfectBinaryTree(root);
if (isPerfect) {
cout << "Yes" << endl;
}
else {
cout << "No" << endl;
}
return 0;
}
|
Java
import java.util.LinkedList;
import java.util.Queue;
import java.util.Vector;
class Node {
int data;
Node left;
Node right;
Node( int data) {
this .data = data;
left = right = null ;
}
}
class Main {
static boolean isPerfectBinaryTree(Node root) {
if (root == null ) {
return true ;
}
Queue<Node> q = new LinkedList<>();
q.add(root);
int level = 1 ;
int flag = 1 ;
while (!q.isEmpty()) {
int size = q.size();
Vector<Integer> levelValues = new Vector<>();
for ( int i = 0 ; i < size; i++) {
Node temp = q.poll();
levelValues.add(temp.data);
if (temp.left != null ) {
q.add(temp.left);
}
if (temp.right != null ) {
q.add(temp.right);
}
}
if (levelValues.size() != 0 && levelValues.size() != level) {
flag = 0 ;
}
level = level * 2 ;
}
return flag == 1 ;
}
public static void main(String[] args) {
Node root = new Node( 7 );
root.left = new Node( 4 );
root.right = new Node( 9 );
boolean isPerfect = isPerfectBinaryTree(root);
if (isPerfect) {
System.out.println( "Yes" );
} else {
System.out.println( "No" );
}
}
}
|
Python3
from queue import Queue
class Node:
def __init__( self , data):
self .data = data
self .left = None
self .right = None
def isPerfectBinaryTree(root):
if root is None :
return True
q = Queue()
q.put(root)
level = 1
flag = 1
while not q.empty():
size = q.qsize()
level_values = []
for i in range (size):
temp = q.get()
level_values.append(temp.data)
if temp.left:
q.put(temp.left)
if temp.right:
q.put(temp.right)
if len (level_values) ! = 0 and len (level_values) ! = level:
flag = 0
level * = 2
return flag
def createNode(data):
new_node = Node(data)
return new_node
if __name__ = = "__main__" :
root = createNode( 7 )
root.left = createNode( 4 )
root.right = createNode( 9 )
is_perfect = isPerfectBinaryTree(root)
if is_perfect:
print ( "Yes" )
else :
print ( "No" )
|
C#
using System;
using System.Collections.Generic;
public class Node {
public int data;
public Node left;
public Node right;
}
public class PerfectBinaryTreeChecker {
public static bool IsPerfectBinaryTree(Node root)
{
if (root == null ) {
return true ;
}
Queue<Node> q = new Queue<Node>();
q.Enqueue(root);
int level = 1;
int flag = 1;
while (q.Count > 0) {
int size = q.Count;
List< int > levelValues = new List< int >();
for ( int i = 0; i < size; i++) {
Node temp = q.Dequeue();
levelValues.Add(temp.data);
if (temp.left != null ) {
q.Enqueue(temp.left);
}
if (temp.right != null ) {
q.Enqueue(temp.right);
}
}
if (levelValues.Count != 0
&& levelValues.Count != level) {
flag = 0;
}
level = level * 2;
}
return flag == 1;
}
public static Node CreateNode( int data)
{
Node newNode = new Node();
if (newNode != null ) {
newNode.data = data;
newNode.left = newNode.right = null ;
}
return newNode;
}
public static void Main( string [] args)
{
Node root = CreateNode(7);
root.left = CreateNode(4);
root.right = CreateNode(9);
bool isPerfect = IsPerfectBinaryTree(root);
if (isPerfect) {
Console.WriteLine( "Yes" );
}
else {
Console.WriteLine( "No" );
}
}
}
|
Javascript
class Node {
constructor(data) {
this .data = data;
this .left = null ;
this .right = null ;
}
}
function isPerfectBinaryTree(root) {
if (!root) {
return true ;
}
let queue = [root];
let level = 1;
let flag = 1;
while (queue.length > 0) {
const size = queue.length;
const levelValues = [];
for (let i = 0; i < size; i++) {
const temp = queue.shift();
levelValues.push(temp.data);
if (temp.left) {
queue.push(temp.left);
}
if (temp.right) {
queue.push(temp.right);
}
}
if (levelValues.length !== 0 && levelValues.length !== level) {
flag = 0;
}
level *= 2;
}
return flag === 1;
}
function createNode(data) {
return new Node(data);
}
( function main() {
const root = createNode(7);
root.left = createNode(4);
root.right = createNode(9);
const isPerfect = isPerfectBinaryTree(root);
if (isPerfect) {
console.log( "Yes" );
} else {
console.log( "No" );
}
})();
|
Time Complexity: O(N), O(N), where N is the number of nodes in the binary tree. This is because we perform a level-order traversal of the tree using a queue, visiting each node once.
Auxiliary Space: O(N), O(M), where M is the maximum number of nodes at any level in the binary tree. In the worst case, a perfect binary tree will have N/2 nodes at the last level, resulting in M = N/2. Hence, the space complexity can be simplified to O(N).
Please Login to comment...