A complete binary tree is defined as a binary tree in which every level, except possibly the deepest, is completely filled. At deepest level, all nodes must be as far left a
For a tree to be complete
height(left) == height(right) or height(left) == 1+height(right)
bool isComplete (struct Node* root){
if(root==NULL)
return true; // Recur for left and right subtree
bool flag=false;
int option1=height(root->left);
int option2=height(root->right);
if(option1==option2||option1==option2+1)
flag=true;
return flag&&isComplete(root->left)&&isComplete(root->right);
}
The following code simply treats every possible cases. Tree height is obtained along the way to avoid another recursion.
enum CompleteType
{
kNotComplete = 0,
kComplete = 1, // Complete but not full
kFull = 2,
kEmpty = 3
};
CompleteType isTreeComplete(Node* node, int* height)
{
if (node == NULL)
{
*height = 0;
return kEmpty;
}
int leftHeight, rightHeight;
CompleteType leftCompleteType = isTreeComplete(node->left, &leftHeight);
CompleteType rightCompleteType = isTreeComplete(node->right, &rightHeight);
*height = max(leftHeight, rightHeight) + 1;
// Straight forwardly treat all possible cases
if (leftCompleteType == kComplete &&
rightCompleteType == kEmpty &&
leftHeight == rightHeight + 1)
return kComplete;
if (leftCompleteType == Full)
{
if (rightCompleteType == kEmpty && leftHeight == rightHeight + 1)
return kComplete;
if (leftHeight == rightHeight)
{
if (rightCompleteType == kComplete)
return kComplete;
if (rightCompleteType == kFull)
return kFull;
}
}
if (leftCompleteType == kEmpty && rightCompleteType == kEmpty)
return kFull;
return kNotComplete;
}
bool isTreeComplete(Node* node)
{
int height;
return (isTreeComplete(node, &height) != kNotComplete);
}
int height (node* tree, int *max, int *min) {
int lh = 0 , rh = 0 ;
if ( tree == NULL )
return 0;
lh = height (tree->left,max,min) ;
rh = height (tree->right,max,min) ;
*max = ((lh>rh) ? lh : rh) + 1 ;
*min = ((lh>rh) ? rh : lh) + 1 ;
return *max ;
}
void isCompleteUtil (node* tree, int height, int* finish, int *complete) {
int lh, rh ;
if ( tree == NULL )
return ;
if ( height == 2 ) {
if ( *finish ) {
if ( !*complete )
return;
if ( tree->left || tree->right )
*complete = 0 ;
return ;
}
if ( tree->left == NULL && tree->right != NULL ) {
*complete = 0 ;
*finish = 1 ;
}
else if ( tree->left == NULL && tree->right == NULL )
*finish = 1 ;
return ;
}
isCompleteUtil ( tree->left, height-1, finish, complete ) ;
isCompleteUtil ( tree->right, height-1, finish, complete ) ;
}
int isComplete (node* tree) {
int max, min, finish=0, complete = 1 ;
height (tree, &max, &min) ;
if ( (max-min) >= 2 )
return 0 ;
isCompleteUtil (tree, max, &finish, &complete) ;
return complete ;
}
There may be one possible algorithm which I feel would solve this problem. Consider the tree:
Level 0: a
Level 1: b c
Level 2: d e f g
We employ breadth first traversal.
For each enqueued element in the queue we have to make three checks in order:
Advantage: entire tree may not be traversed
Overhead: maintaining flag entries
Similar to:
height(t) = if (t==NULL) then 0 else 1+max(height(t.left),height(t.right))
You have:
perfect(t) = if (t==NULL) then 0 else {
let h=perfect(t.left)
if (h != -1 && h==perfect(t.right)) then 1+h else -1
}
Where perfect(t) returns -1 if the leaves aren't all at the same depth, or any node has only one child; otherwise, it returns the height.
Edit: this is for "complete" = "A perfect binary tree is a full binary tree in which all leaves are at the same depth or same level.1 (This is ambiguously also called a complete binary tree.)" (Wikipedia).
Here's a recursive check for: "A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.". It returns (-1,false) if the tree isn't complete, otherwise (height,full) if it is, with full==true iff it's perfect.
complete(t) = if (t==NULL) then (0,true) else {
let (hl,fl)=complete(t.left)
let (hr,fr)=complete(t.right)
if (fl && hl==hr) then (1+h,fr)
else if (fr && hl==hr+1) then (1+h,false)
else (-1,false)
}
Thanks for @Jonathan Graehl 's pseudo code. I've implemented it in Java. I've tested it against iterative version. It works like a charm!
public static boolean isCompleteBinaryTreeRec(TreeNode root){
// Pair notComplete = new Pair(-1, false);
// return !isCompleteBinaryTreeSubRec(root).equalsTo(notComplete);
return isCompleteBinaryTreeSubRec(root).height != -1;
}
public static boolean isPerfectBinaryTreeRec(TreeNode root){
return isCompleteBinaryTreeSubRec(root).isFull;
}
public static Pair isCompleteBinaryTreeSubRec(TreeNode root){
if(root == null){
return new Pair(0, true);
}
Pair left = isCompleteBinaryTreeSubRec(root.left);
Pair right = isCompleteBinaryTreeSubRec(root.right);
if(left.isFull && left.height==right.height){
return new Pair(1+left.height, right.isFull);
}
if(right.isFull && left.height==right.height+1){
return new Pair(1+left.height, false);
}
return new Pair(-1, false);
}
private static class Pair{
int height;
boolean isFull;
public Pair(int height, boolean isFull) {
this.height = height;
this.isFull = isFull;
}
public boolean equalsTo(Pair obj){
return this.height==obj.height && this.isFull==obj.isFull;
}
}