A complete binary tree is a binary tree where each level 'l' except the last has 2^l nodes and the nodes at the last level are all left-aligned. Complete binary trees are mainly used in heap-based data structures.
The nodes in the complete binary tree are inserted from left to right in one level at a time. If a level is full, the node is inserted in a new level.
Below are some complete binary trees.
1
/ \
2 3
1
/ \
2 3
/ \ /
4 5 6
Below binary trees are not complete:
1
/ \
2 3
/ /
4 5
1
/ \
2 3
/ \ /
4 5 6
/
7
Complete binary trees are generally represented using arrays. The array representation is better because it doesn't contain any empty slots. Given parent index i, its left child is given by 2 * i + 1, and its right child is given by 2 * i + 2. So no extra space is wasted and space to store left and right pointers is saved. However, it may be an interesting programming question to create a Complete Binary Tree using linked representation. Here Linked means a non-array representation where the left and right pointers(or references) are used to refer left and right children respectively. How to write an insert function that always adds a new node in the last level and at the leftmost available position?
To create a linked complete binary tree, we need to keep track of the nodes in a level order fashion such that the next node to be inserted lies in the leftmost position. A queue data structure can be used to keep track of the inserted nodes.
The following are steps to insert a new node in Complete Binary Tree.
- If the tree is empty, initialize the root with a new node.
- Else, get the front node of the queue.
- .......If the left child of this front node doesn't exist, set the left child as the new node.
- .......else if the right child of this front node doesn't exist, set the right child as the new node.
- If the front node has both the left child and right child, Dequeue() it.
- Enqueue() the new node.
Below is the implementation:
// Program for linked implementation of complete binary tree
#include <bits/stdc++.h>
using namespace std;
// For Queue Size
#define SIZE 50
// A tree node
class node
{
public:
int data;
node *right,*left;
};
// A queue node
class Queue
{
public:
int front, rear;
int size;
node**array;
};
// A utility function to create a new tree node
node* newNode(int data)
{
node* temp = new node();
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
// A utility function to create a new Queue
Queue* createQueue(int size)
{
Queue* queue = new Queue();
queue->front = queue->rear = -1;
queue->size = size;
queue->array = new node*[queue->size * sizeof( node* )];
int i;
for (i = 0; i < size; ++i)
queue->array[i] = NULL;
return queue;
}
// Standard Queue Functions
int isEmpty(Queue* queue)
{
return queue->front == -1;
}
int isFull(Queue* queue)
{ return queue->rear == queue->size - 1; }
int hasOnlyOneItem(Queue* queue)
{ return queue->front == queue->rear; }
void Enqueue(node *root, Queue* queue)
{
if (isFull(queue))
return;
queue->array[++queue->rear] = root;
if (isEmpty(queue))
++queue->front;
}
node* Dequeue(Queue* queue)
{
if (isEmpty(queue))
return NULL;
node* temp = queue->array[queue->front];
if (hasOnlyOneItem(queue))
queue->front = queue->rear = -1;
else
++queue->front;
return temp;
}
node* getFront(Queue* queue)
{ return queue->array[queue->front]; }
// A utility function to check if a tree node
// has both left and right children
int hasBothChild(node* temp)
{
return temp && temp->left && temp->right;
}
// Function to insert a new node in complete binary tree
void insert(node **root, int data, Queue* queue)
{
// Create a new node for given data
node *temp = newNode(data);
// If the tree is empty, initialize the root with new node.
if (!*root)
*root = temp;
else
{
// get the front node of the queue.
node* front = getFront(queue);
// If the left child of this front node doesn’t exist, set the
// left child as the new node
if (!front->left)
front->left = temp;
// If the right child of this front node doesn’t exist, set the
// right child as the new node
else if (!front->right)
front->right = temp;
// If the front node has both the left child and right child,
// Dequeue() it.
if (hasBothChild(front))
Dequeue(queue);
}
// Enqueue() the new node for later insertions
Enqueue(temp, queue);
}
// Standard level order traversal to test above function
void levelOrder(node* root)
{
Queue* queue = createQueue(SIZE);
Enqueue(root, queue);
while (!isEmpty(queue))
{
node* temp = Dequeue(queue);
cout<<temp->data<<" ";
if (temp->left)
Enqueue(temp->left, queue);
if (temp->right)
Enqueue(temp->right, queue);
}
}
// Driver program to test above functions
int main()
{
node* root = NULL;
Queue* queue = createQueue(SIZE);
int i;
for(i = 1; i <= 12; ++i)
insert(&root, i, queue);
levelOrder(root);
return 0;
}
//This code is contributed by rathbhupendra
// Program for linked implementation of complete binary tree
#include <stdio.h>
#include <stdlib.h>
// For Queue Size
#define SIZE 50
// A tree node
struct node
{
int data;
struct node *right,*left;
};
// A queue node
struct Queue
{
int front, rear;
int size;
struct node* *array;
};
// A utility function to create a new tree node
struct node* newNode(int data)
{
struct node* temp = (struct node*) malloc(sizeof( struct node ));
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
// A utility function to create a new Queue
struct Queue* createQueue(int size)
{
struct Queue* queue = (struct Queue*) malloc(sizeof( struct Queue ));
queue->front = queue->rear = -1;
queue->size = size;
queue->array = (struct node**) malloc
(queue->size * sizeof( struct node* ));
int i;
for (i = 0; i < size; ++i)
queue->array[i] = NULL;
return queue;
}
// Standard Queue Functions
int isEmpty(struct Queue* queue)
{
return queue->front == -1;
}
int isFull(struct Queue* queue)
{ return queue->rear == queue->size - 1; }
int hasOnlyOneItem(struct Queue* queue)
{ return queue->front == queue->rear; }
void Enqueue(struct node *root, struct Queue* queue)
{
if (isFull(queue))
return;
queue->array[++queue->rear] = root;
if (isEmpty(queue))
++queue->front;
}
struct node* Dequeue(struct Queue* queue)
{
if (isEmpty(queue))
return NULL;
struct node* temp = queue->array[queue->front];
if (hasOnlyOneItem(queue))
queue->front = queue->rear = -1;
else
++queue->front;
return temp;
}
struct node* getFront(struct Queue* queue)
{ return queue->array[queue->front]; }
// A utility function to check if a tree node
// has both left and right children
int hasBothChild(struct node* temp)
{
return temp && temp->left && temp->right;
}
// Function to insert a new node in complete binary tree
void insert(struct node **root, int data, struct Queue* queue)
{
// Create a new node for given data
struct node *temp = newNode(data);
// If the tree is empty, initialize the root with new node.
if (!*root)
*root = temp;
else
{
// get the front node of the queue.
struct node* front = getFront(queue);
// If the left child of this front node doesn’t exist, set the
// left child as the new node
if (!front->left)
front->left = temp;
// If the right child of this front node doesn’t exist, set the
// right child as the new node
else if (!front->right)
front->right = temp;
// If the front node has both the left child and right child,
// Dequeue() it.
if (hasBothChild(front))
Dequeue(queue);
}
// Enqueue() the new node for later insertions
Enqueue(temp, queue);
}
// Standard level order traversal to test above function
void levelOrder(struct node* root)
{
struct Queue* queue = createQueue(SIZE);
Enqueue(root, queue);
while (!isEmpty(queue))
{
struct node* temp = Dequeue(queue);
printf("%d ", temp->data);
if (temp->left)
Enqueue(temp->left, queue);
if (temp->right)
Enqueue(temp->right, queue);
}
}
// Driver program to test above functions
int main()
{
struct node* root = NULL;
struct Queue* queue = createQueue(SIZE);
int i;
for(i = 1; i <= 12; ++i)
insert(&root, i, queue);
levelOrder(root);
return 0;
}
// Java code for the above approach
import java.util.LinkedList;
import java.util.Queue;
class Node {
int data;
Node left, right;
public Node(int data) {
this.data = data;
left = right = null;
}
}
public class CompleteBinaryTree {
Node root;
public CompleteBinaryTree() {
root = null;
}
// A utility function to create a new tree node
Node newNode(int data) {
Node temp = new Node(data);
return temp;
}
// Function to insert a new node in complete binary tree
void insert(int data) {
// Create a new node for given data
Node temp = newNode(data);
// If the tree is empty, initialize the root with new node.
if (root == null) {
root = temp;
return;
}
// Create a queue to do level order traversal
Queue<Node> q = new LinkedList<>();
q.add(root);
// Do level order traversal
while (!q.isEmpty()) {
Node front = q.peek();
// If the left child of this front node doesn't exist, set the
// left child as the new node
if (front.left == null) {
front.left = temp;
break;
}
// If the right child of this front node doesn't exist, set the
// right child as the new node
else if (front.right == null) {
front.right = temp;
break;
}
// If the front node has both the left child and right child,
// remove it from the queue
else {
q.remove();
}
// Enqueue the left and right children of the current node
if (front.left != null) {
q.add(front.left);
}
if (front.right != null) {
q.add(front.right);
}
}
}
// Standard level order traversal to test above function
void levelOrder() {
if (root == null) {
return;
}
Queue<Node> q = new LinkedList<>();
q.add(root);
while (!q.isEmpty()) {
Node temp = q.poll();
System.out.print(temp.data + " ");
if (temp.left != null) {
q.add(temp.left);
}
if (temp.right != null) {
q.add(temp.right);
}
}
}
public static void main(String[] args) {
CompleteBinaryTree tree = new CompleteBinaryTree();
for (int i = 1; i <= 12; i++) {
tree.insert(i);
}
tree.levelOrder();
}
}
// This code is contributed by ik_7
# Program for linked implementation
# of complete binary tree
# For Queue Size
SIZE = 50
# A tree node
class node:
def __init__(self, data):
self.data = data
self.right = None
self.left = None
# A queue node
class Queue:
def __init__(self):
self.front = None
self.rear = None
self.size = 0
self.array = []
# A utility function to
# create a new tree node
def newNode(data):
temp = node(data)
return temp
# A utility function to
# create a new Queue
def createQueue(size):
global queue
queue = Queue();
queue.front = queue.rear = -1;
queue.size = size;
queue.array = [None for i in range(size)]
return queue;
# Standard Queue Functions
def isEmpty(queue):
return queue.front == -1
def isFull(queue):
return queue.rear == queue.size - 1;
def hasOnlyOneItem(queue):
return queue.front == queue.rear;
def Enqueue(root):
if (isFull(queue)):
return;
queue.rear+=1
queue.array[queue.rear] = root;
if (isEmpty(queue)):
queue.front+=1;
def Dequeue():
if (isEmpty(queue)):
return None;
temp = queue.array[queue.front];
if(hasOnlyOneItem(queue)):
queue.front = queue.rear = -1;
else:
queue.front+=1
return temp;
def getFront(queue):
return queue.array[queue.front];
# A utility function to check
# if a tree node has both left
# and right children
def hasBothChild(temp):
return (temp and temp.left and
temp.right);
# Function to insert a new
# node in complete binary tree
def insert(root, data, queue):
# Create a new node for
# given data
temp = newNode(data);
# If the tree is empty,
# initialize the root
# with new node.
if not root:
root = temp;
else:
# get the front node of
# the queue.
front = getFront(queue);
# If the left child of this
# front node doesn’t exist,
# set the left child as the
# new node
if (not front.left):
front.left = temp;
# If the right child of this
# front node doesn’t exist, set
# the right child as the new node
elif (not front.right):
front.right = temp;
# If the front node has both the
# left child and right child,
# Dequeue() it.
if (hasBothChild(front)):
Dequeue();
# Enqueue() the new node for
# later insertions
Enqueue(temp);
return root
# Standard level order
# traversal to test above
# function
def levelOrder(root):
queue = createQueue(SIZE);
Enqueue(root);
while (not isEmpty(queue)):
temp = Dequeue();
print(temp.data, end = ' ')
if (temp.left):
Enqueue(temp.left);
if (temp.right):
Enqueue(temp.right);
# Driver code
if __name__ == "__main__":
root = None
queue = createQueue(SIZE);
for i in range(1, 13):
root=insert(root, i,
queue);
levelOrder(root);
# This code is contributed by Rutvik_56
using System;
using System.Collections.Generic;
class Node
{
public int data;
public Node left, right;
public Node(int data)
{
this.data = data;
left = right = null;
}
}
class CompleteBinaryTree
{
Node root;
public CompleteBinaryTree()
{
root = null;
}
// A utility function to create a new tree node
Node newNode(int data)
{
Node temp = new Node(data);
return temp;
}
// Function to insert a new node in complete binary tree
void insert(int data)
{
// Create a new node for given data
Node temp = newNode(data);
// If the tree is empty, initialize the root with new node.
if (root == null)
{
root = temp;
return;
}
// Create a queue to do level order traversal
Queue<Node> q = new Queue<Node>();
q.Enqueue(root);
// Do level order traversal
while (q.Count > 0)
{
Node front = q.Peek();
// If the left child of this front node doesn't exist, set the
// left child as the new node
if (front.left == null)
{
front.left = temp;
break;
}
// If the right child of this front node doesn't exist, set the
// right child as the new node
else if (front.right == null)
{
front.right = temp;
break;
}
// If the front node has both the left child and right child,
// remove it from the queue
else
{
q.Dequeue();
}
// Enqueue the left and right children of the current node
if (front.left != null)
{
q.Enqueue(front.left);
}
if (front.right != null)
{
q.Enqueue(front.right);
}
}
}
// Standard level order traversal to test above function
void levelOrder()
{
if (root == null)
{
return;
}
Queue<Node> q = new Queue<Node>();
q.Enqueue(root);
while (q.Count > 0)
{
Node temp = q.Dequeue();
Console.Write(temp.data + " ");
if (temp.left != null)
{
q.Enqueue(temp.left);
}
if (temp.right != null)
{
q.Enqueue(temp.right);
}
}
}
// Driver program to test above functions
static void Main(string[] args)
{
CompleteBinaryTree tree = new CompleteBinaryTree();
for (int i = 1; i <= 12; i++)
{
tree.insert(i);
}
tree.levelOrder();
}
}
// This code is contributed by Vaibhav.
<script>
// Program for linked implementation
// of complete binary tree
// For Queue Size
const SIZE = 50;
// A tree node
class Node {
constructor(data) {
this.data = data;
this.left = null;
this.right = null;
}
}
class Queue {
constructor(size) {
this.front = -1;
this.rear = -1;
this.size = size;
this.array = new Array(size);
}
// Standard Queue Functions
isEmpty() {
return this.front === -1;
}
isFull() {
return this.rear === this.size - 1;
}
hasOnlyOneItem() {
return this.front === this.rear;
}
enqueue(root) {
if (this.isFull()) {
return;
}
this.rear++;
this.array[this.rear] = root;
if (this.isEmpty()) {
this.front++;
}
}
dequeue() {
if (this.isEmpty()) {
return null;
}
let temp = this.array[this.front];
if (this.hasOnlyOneItem()) {
this.front = this.rear = -1;
} else {
this.front++;
}
return temp;
}
getFront() {
return this.array[this.front];
}
}
// A utility function to create a new tree node
function newNode(data) {
return new Node(data);
}
// A utility function to create a new Queue
function createQueue(size) {
let queue = new Queue(size);
return queue;
}
// A utility function to check if a tree node has both left and right children
function hasBothChild(temp) {
return temp && temp.left && temp.right;
}
// Function to insert a new node in complete binary tree
function insert(root, data, queue) {
let temp = newNode(data);
// If the tree is empty, initialize the root with new node.
if (!root) {
root = temp;
} else {
// get the front node of the queue.
let front = queue.getFront();
if (!front.left) {
front.left = temp;
} else if (!front.right) {
front.right = temp;
}
// If the front node has both the left child and right child, Dequeue() it.
if (hasBothChild(front)) {
queue.dequeue();
}
}
// Enqueue() the new node for later insertions
queue.enqueue(temp);
return root;
}
// Standard level order traversal to test above function
function levelOrder(root) {
let queue = createQueue(50);
queue.enqueue(root);
while (!queue.isEmpty()) {
let temp = queue.dequeue();
document.write(temp.data);
if (temp.left) {
queue.enqueue(temp.left);
}
if (temp.right) {
queue.enqueue(temp.right);
}
}
}
let root = null;
let queue = createQueue(50);
for (let i = 1; i < 13; i++) {
root = insert(root, i, queue);
}
levelOrder(root);
</script>
Output:
1 2 3 4 5 6 7 8 9 10 11 12