Binary Tree Data Structure
Binary Tree Data Structure
A tree whose elements have at most 2 children is called a binary tree. Since each
element in a binary tree can have only 2 children, we typically name them the left
and right child.
file system
-----------
/ <-- root
/ \
... home
/ \
ugrad course
/ / | \
... cs101 cs112 cs113
2. Trees (with some ordering e.g., BST) provide moderate access/search (quicker
than Linked List and slower than arrays).
3. Trees provide moderate insertion/deletion (quicker than Arrays and slower than
Unordered Linked Lists).
4. Like Linked Lists and unlike Arrays, Trees don’t have an upper limit on number of
nodes as nodes are linked using pointers.
Main applications of trees include:
1. Manipulate hierarchical data.
2. Make information easy to search (see tree traversal).
3. Manipulate sorted lists of data.
4. As a workflow for compositing digital images for visual effects.
5. Router algorithms
6. Form of a multi-stage decision-making (see business chess).
Binary Tree: A tree whose elements have at most 2 children is called a binary tree.
Since each element in a binary tree can have only 2 children, we typically name them
the left and right child.
Binary Tree Representation in C: A tree is represented by a pointer to the topmost
node in tree. If the tree is empty, then value of root is NULL.
A Tree node contains following parts.
1. Data
2. Pointer to left child
3. Pointer to right child
/* Class containing left and right child of current
node and key value*/
class Node
{
int key;
Node left, right;
public Node(int item)
{
key = item;
left = right = null;
}
}
// A Java program to introduce Binary Tree
class BinaryTree
{
// Root of Binary Tree
Node root;
// Constructors
BinaryTree(int key)
{
root = new Node(key);
}
BinaryTree()
{
root = null;
}
public static void main(String[] args)
{
BinaryTree tree = new BinaryTree();
/*create root*/
tree.root = new Node(1);
/* following is the tree after above statement
1
/ \
null null */
tree.root.left = new Node(2);
tree.root.right = new Node(3);
/* 2 and 3 become left and right children of 1
1
/ \
2 3
/ \ / \
null null null null */
tree.root.left.left = new Node(4);
/* 4 becomes left child of 2
1
/ \
2 3
/ \ / \
4 null null null
/ \
null null
*/
}
}
Summary: Tree is a hierarchical data structure. Main uses of trees include
maintaining hierarchical data, providing moderate access and insert/delete
operations. Binary trees are special cases of tree where every node has at most two
children.
3) In a Binary Tree with N nodes, minimum possible height or minimum number of
levels is ? Log2(N+1) ?
This can be directly derived from point 2 above. If we consider the convention where
height of a leaf node is considered as 0, then above formula for minimum possible
height becomes ? Log2(N+1) ? – 1
4) A Binary Tree with L leaves has at least ? Log2L ? + 1 levels
A Binary tree has maximum number of leaves (and minimum number of levels) when
all levels are fully filled. Let all leaves be at level l, then below is true for number of
leaves L.
L <= 2l-1 [From Point 1]
l = ? Log2L ? + 1
where l is the minimum number of levels.
5) In Binary tree where every node has 0 or 2 children, number of leaf nodes is
always one more than nodes with two children.
L=T+1
Where L = Number of leaf nodes
T = Number of internal nodes with two children
18
/ \
15 30
/ \ / \
40 50 100 40
18
/ \
15 20
/ \
40 50
/ \
30 50
18
/ \
40 30
/ \
100 40
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
Following are examples of Complete Binary Trees
18
/ \
15 30
/ \ / \
40 50 100 40
18
/ \
15 30
/ \ / \
40 50 100 40
/ \ /
8 7 9
Practical example of Complete Binary Tree is Binary Heap.
Perfect Binary Tree A Binary tree is Perfect Binary Tree in which all internal nodes
have two children and all leaves are at the same level.
Following are examples of Perfect Binary Trees.
18
/ \
15 30
/ \ / \
40 50 100 40
18
/ \
15 30
A Perfect Binary Tree of height h (where height is the number of nodes on the path
from the root to leaf) has 2h – 1 node.
Example of a Perfect binary tree is ancestors in the family. Keep a person at root,
parents as children, parents of parents as their children.
A degenerate (or pathological) tree A Tree where every internal node has one child.
Such trees are performance-wise same as linked list.
10
/
20
\
30
\
40
L = (k - 1)*I + 1
Where L = Number of leaf nodes
I = Number of internal nodes
Proof:
Proof can be divided in two cases.
Case 1 (Root is Leaf):There is only one node in tree. The above formula is true for
single node as L = 1, I = 0.
Case 2 (Root is Internal Node): For trees with more than 1 nodes, root is always
internal node. The above formula can be proved using Handshaking Lemma for this
case. A tree is an undirected acyclic graph.
Total number of edges in Tree is number of nodes minus 1, i.e., |E| = L + I – 1.
All internal nodes except root in the given type of tree have degree k + 1. Root has
degree k. All leaves have degree 1. Applying the Handshaking lemma to such trees,
we get following relation.
Sum of all degrees = 2 * (Sum of Edges)
L=T+1
Where L = Number of leaf nodes
T = Number of internal nodes with two children
Proof:
Let number of nodes with 2 children be T. Proof can be divided in three cases.
Case 1: There is only one node, the relationship holds
as T = 0, L = 1.
Case 2: Root has two children, i.e., degree of root is 2.
Sum of degrees of nodes with two children except root +
Sum of degrees of nodes with one child +
Sum of degrees of leaves + Root's degree = 2 * (No. of Nodes - 1)
Here,
T(i-1) represents number of nodes on the left-sub-tree
T(n−i-1) represents number of nodes on the right-sub-tree
n’th Catalan Number can also be evaluated using direct formula.
T(n) = (2n)! / (n+1)!n!
Number of Binary Search Trees (BST) with n nodes is also same as number of
unlabeled trees. The reason for this is simple, in BST also we can make any key as
root, If root is i’th key in sorted order, then i-1 keys can go on one side and (n-i) keys
can go on other side.
How many labeled Binary Trees can be there with n nodes?
To count labeled trees, we can use above count for unlabeled trees. The idea is
simple, every unlabeled tree with n nodes can create n! different labeled trees by
assigning different permutations of labels to all nodes.
Therefore,
Number of Labeled Tees = (Number of unlabeled trees) * n!
= [(2n)! / (n+1)!n!] × n!
For example for n = 3, there are 5 * 3! = 5*6 = 30 different labeled trees
Please write comments if you find anything incorrect, or you want to share more
information about the topic discussed above
The idea is to do iterative level order traversal of the given tree using queue. If we
find a node whose left child is empty, we make new key as left child of the node. Else
if we find a node whose right child is empty, we make new key as right child. We
keep traversing the tree until we find a node whose either left or right is empty.
// Java program to insert element in binary tree
import java.util.LinkedList;
import java.util.Queue;
public class GFG {
/* A binary tree node has key, pointer to
left child and a pointer to right child */
static class Node {
int key;
Node left, right;
// constructor
Node(int key){
this.key = key;
left = null;
right = null;
}
}
static Node root;
static Node temp = root;
/* Inorder traversal of a binary tree*/
static void inorder(Node temp)
{
if (temp == null)
return;
inorder(temp.left);
System.out.print(temp.key+" ");
inorder(temp.right);
}
/*function to insert element in binary tree */
static void insert(Node temp, int key)
{
Queue<Node> q = new LinkedList<Node>();
q.add(temp);
// Do level order traversal until we find
// an empty place.
while (!q.isEmpty()) {
temp = q.peek();
q.remove();
if (temp.left == null) {
temp.left = new Node(key);
break;
} else
q.add(temp.left);
if (temp.right == null) {
temp.right = new Node(key);
break;
} else
q.add(temp.right);
}
}
// Driver code
public static void main(String args[])
{
root = new Node(10);
root.left = new Node(11);
root.left.left = new Node(7);
root.right = new Node(9);
root.right.left = new Node(15);
root.right.right = new Node(8);
System.out.print( "Inorder traversal before insertion:");
inorder(root);
int key = 12;
insert(root, key);
System.out.print("\nInorder traversal after insertion:");
inorder(root);
}
}
Output:
Inorder traversal before insertion: 7 11 10 15 9 8
Inorder traversal after insertion: 7 11 12 10 15 9 8
Why Tree?
Unlike Array and Linked List, which are linear data structures, tree is hierarchical (or
non-linear) data structure.
1. One reason to use trees might be because you want to store information that
naturally forms a hierarchy. For example, the file system on a computer:
file system
———–
2.
/ <-- root
/ \
... home
/ \
ugrad course
/ / | \
... cs101 cs112 cs113
3.
4. If we organize keys in form of a tree (with some ordering e.g., BST), we can
search for a given key in moderate time (quicker than Linked List and slower
than arrays). Self-balancing search trees like AVL and Red-Black
trees guarantee an upper bound of O(Logn) for search.
5. We can insert/delete keys in moderate time (quicker than Arrays and slower
than Unordered Linked Lists). Self-balancing search trees like AVL and Red-
Black trees guarantee an upper bound of O(Logn) for insertion/deletion.
6. Like Linked Lists and unlike Arrays, Pointer implementation of trees don’t
have an upper limit on number of nodes as nodes are linked using pointers.
Other Applications :
1. Heap is a tree data structure which is implemented using arrays and used to
implement priority queues.
2. B-Tree and B+ Tree : They are used to implement indexing in databases.
3. Syntax Tree: Used in Compilers.
4. K-D Tree: A space partitioning tree used to organize points in K dimensional
space.
5. Trie : Used to implement dictionaries with prefix lookup.
6. Suffix Tree : For quick pattern searching in a fixed text.
Traversals :
Example Tree
1
/ \
2 3
/ \
4 5
Step 3 Pushes the current node and set current = current->left until current is NULL
current -> 1
push 1: Stack S -> 1
current -> 2
push 2: Stack S -> 2, 1
current -> 4
push 4: Stack S -> 4, 2, 1
current = NULL
Step 4 pops from S
a) Pop 4: Stack S -> 2, 1
b) print "4"
c) current = NULL /*right of 4 */ and go to step 3
Since current is NULL step 3 doesn't do anything.
Output:
42513
Time Complexity: O(n)
Input : n = 3
7
/ \
2 3
/ \
8 5
Output : 8
Inorder: 2 7 8 3 5
3th node is 8
We do simple Inorder Traversal. While doing the traversal, we keep track of count of
nodes visited so far. When count becomes n, we print the node.
Below is the implementation of above approach.
// Java program for nth nodes of inorder traversals
import java.util. *;
class Solution
{
static int count =0;
/* A binary tree node has data, pointer to left child
and a pointer to right child */
static class Node {
int data;
Node left;
Node right;
}
/* Helper function that allocates a new node with the
given data and null left and right pointers. */
static Node newNode(int data)
{
Node node = new Node();
node.data = data;
node.left = null;
node.right = null;
return (node);
}
/* Given a binary tree, print its nth nodes of inorder*/
static void NthInorder( Node node, int n)
{
if (node == null)
return;
if (count <= n) {
/* first recur on left child */
NthInorder(node.left, n);
count++;
// when count = n then print element
if (count == n)
System.out.printf("%d ", node.data);
/* now recur on right child */
NthInorder(node.right, n);
}
}
/* Driver program to test above functions*/
public static void main(String args[])
{
Node root = newNode(10);
root.left = newNode(20);
root.right = newNode(30);
root.left.left = newNode(40);
root.left.right = newNode(50);
int n = 4;
NthInorder(root, n);
}
}
Output:
10
Time Complexity: O(n)
Example Tree
Output:
10 8 3 5 2 2
Output:
Inorder traversal of the constructed tree is
4 8 10 12 14 20 22
An upper bound on time complexity of above method is O(n3). In the main recursive
function, extractNodes() is called which takes O(n 2) time.
Construct Complete Binary Tree from its
Linked List Representation
Given Linked List Representation of Complete Binary Tree, construct the Binary tree.
A complete binary tree can be represented in an array in the following approach.
If root node is stored at index i, its left, and right children are stored at indices 2*i+1,
2*i+2 respectively.
Suppose tree is represented by a linked list in same way, how do we convert this into
normal linked representation of binary tree where every node has data, left and right
pointers? In the linked list representation, we cannot directly access the children of
the current node unless we traverse the list.
We are mainly given level order traversal in sequential access form. We know head
of linked list is always is root of the tree. We take the first node as root and we also
know that the next two nodes are left and right children of root. So we know partial
Binary Tree. The idea is to do Level order traversal of the partially built Binary Tree
using queue and traverse the linked list at the same time. At every step, we take the
parent node from queue, make next two nodes of linked list as children of the parent
node, and enqueue the next two nodes to queue.
1. Create an empty queue.
2. Make the first node of the list as root, and enqueue it to the queue.
3. Until we reach the end of the list, do the following.
………a. Dequeue one node from the queue. This is the current parent.
………b. Traverse two nodes in the list, add them as children of the current parent.
………c. Enqueue the two nodes into the queue.
// Java program to create complete Binary Tree from its Linked List
// representation
// importing necessary classes
import java.util.*;
// A linked list node
class ListNode
{
int data;
ListNode next;
ListNode(int d)
{
data = d;
next = null;
}
}
// A binary tree node
class BinaryTreeNode
{
int data;
BinaryTreeNode left, right = null;
BinaryTreeNode(int data)
{
this.data = data;
left = right = null;
}
}
class BinaryTree
{
ListNode head;
BinaryTreeNode root;
// Function to insert a node at the beginning of
// the Linked List
void push(int new_data)
{
// allocate node and assign data
ListNode new_node = new ListNode(new_data);
// link the old list off the new node
new_node.next = head;
// move the head to point to the new node
head = new_node;
}
// converts a given linked list representing a
// complete binary tree into the linked
// representation of binary tree.
BinaryTreeNode convertList2Binary(BinaryTreeNode node)
{
// queue to store the parent nodes
Queue<BinaryTreeNode> q =
new LinkedList<BinaryTreeNode>();
// Base Case
if (head == null)
{
node = null;
return null;
}
// 1.) The first node is always the root node, and
// add it to the queue
node = new BinaryTreeNode(head.data);
q.add(node);
// advance the pointer to the next node
head = head.next;
// until the end of linked list is reached, do the
// following steps
while (head != null)
{
// 2.a) take the parent node from the q and
// remove it from q
BinaryTreeNode parent = q.peek();
BinaryTreeNode pp = q.poll();
// 2.c) take next two nodes from the linked list.
// We will add them as children of the current
// parent node in step 2.b. Push them into the
// queue so that they will be parents to the
// future nodes
BinaryTreeNode leftChild = null, rightChild = null;
leftChild = new BinaryTreeNode(head.data);
q.add(leftChild);
head = head.next;
if (head != null)
{
rightChild = new BinaryTreeNode(head.data);
q.add(rightChild);
head = head.next;
}
// 2.b) assign the left and right children of
// parent
parent.left = leftChild;
parent.right = rightChild;
}
return node;
}
// Utility function to traverse the binary tree
// after conversion
void inorderTraversal(BinaryTreeNode node)
{
if (node != null)
{
inorderTraversal(node.left);
System.out.print(node.data + " ");
inorderTraversal(node.right);
}
}
// Driver program to test above functions
public static void main(String[] args)
{
BinaryTree tree = new BinaryTree();
tree.push(36); /* Last node of Linked List */
tree.push(30);
tree.push(25);
tree.push(15);
tree.push(12);
tree.push(10); /* First node of Linked List */
BinaryTreeNode node = tree.convertList2Binary(tree.root);
System.out.println("Inorder Traversal of the"+
" constructed Binary Tree is:");
tree.inorderTraversal(node);
}
}
Output:
Inorder Traversal of the constructed Binary Tree is:
25 12 30 10 36 15
Time Complexity: Time complexity of the above solution is O(n) where n is the
number of nodes.
Output:
646251636
Time Complexity: O(n), where n is the total number of nodes in the tree.
Summation :
Output:
Sum of all the elements is: 36
The idea is to traverse the tree, starting from root. For every node, check if its left
subtree is a leaf. If it is, then add it to the result.
Output:
Sum of left leaves is 78
Output :
sum = 2 + 5 + 7 = 14
The idea is to traverse the tree starting from the root and check if the node is the
leaf node or not. If the node is the right leaf than add data of right leaf to sum
variable.
Following is the implementation for the same.
// Java program to find total
// sum of right leaf nodes
class GFG
{
// sum
static int sum = 0;
// node of binary tree
static class Node
{
int data;
Node left, right;
};
// return new node
static Node addNode(int data)
{
Node temp = new Node();
temp.data = data;
temp.left = temp.right = null;
return temp;
}
// utility function to calculate
// sum of right leaf nodes
static void rightLeafSum(Node root)
{
if(root == null)
return;
// check if the right child
// of root is leaf node
if(root.right != null)
if(root.right.left == null &&
root.right.right == null)
sum += root.right.data;
rightLeafSum(root.left);
rightLeafSum(root.right);
}
// Driver Code
public static void main(String args[])
{
//contruct binary tree
Node root = addNode(1);
root.left = addNode(2);
root.left.left = addNode(4);
root.left.right = addNode(5);
root.left.left.right = addNode(2);
root.right = addNode(3);
root.right.right = addNode(8);
root.right.right.left = addNode(6);
root.right.right.right = addNode(7);
// variable to store sum
// of right leaves
sum = 0;
rightLeafSum(root);
System.out.println( sum );
}
}
Output:
14