A binary tree is a hierarchical data structure in which each node can have at most two children, known as the left child and the right child. It is one of the most widely used tree data structures and forms the foundation of advanced structures such as Binary Search Trees, Heaps, and Expression Trees.
- Each node in a binary tree can have zero, one, or two children
- The topmost node is called the root, while nodes with no children are called leaf nodes
- Binary trees are commonly used for hierarchical data representation, searching, and expression evaluation
Implementation of Binary Tree in C++
In C++, a binary tree is typically implemented using a node structure or class. Each node stores data along with pointers to its left and right children. These pointers create links between nodes, allowing the tree to represent hierarchical relationships efficiently.
- A node contains a data field to store the value.
- A left pointer stores the address of the left child node.
- A right pointer stores the address of the right child node.
- Nodes are dynamically connected using pointers to form the tree structure.
Representation of Binary Tree
To represent a binary tree in C++, we declare a Node class that contains the data and pointers to its left and right children.

- The Node class represents an individual node of the binary tree
- Each node stores a data value and links to its child nodes
- Templates are used to make the binary tree generic so that it can store different data types
- A BinaryTree class can be used to encapsulate the tree data members and its associated operations
template <typename T>
class Node {
public:
T data;
Node* left;
Node* right;
Each node of a binary tree consists of the following components:
- data - stores the value associated with the node
- left - points to the left child of the current node
- right - points to the right child of the current node
The following program illustrates how we can implement a binary tree in C++.
#include <iostream>
#include <queue>
using namespace std;
// Template class for the Node of a Binary Tree
template <typename T>
class Node {
public:
// Data held by the node
T data;
// Pointer to the left child
Node* left;
// Pointer to the right child
Node* right;
// Constructor to initialize the node with a value
Node(T value) : data(value), left(nullptr), right(nullptr) {}
};
// Template class for a Binary Tree
template <typename T>
class BinaryTree {
private:
// Pointer to the root of the tree
Node<T>* root;
// Recursive Function to delete a node from the tree
Node<T>* deleteRecursive(Node<T>* current, T value) {
if (current == nullptr) return nullptr;
if (current->data == value) {
if (current->left == nullptr && current->right == nullptr) {
delete current;
return nullptr;
}
if (current->left == nullptr) {
Node<T>* temp = current->right;
delete current;
return temp;
}
if (current->right == nullptr) {
Node<T>* temp = current->left;
delete current;
return temp;
}
Node<T>* successor = findMin(current->right);
current->data = successor->data;
current->right = deleteRecursive(current->right, successor->data);
} else {
current->left = deleteRecursive(current->left, value);
current->right = deleteRecursive(current->right, value);
}
return current;
}
// Helper Function to find the minimum value node
Node<T>* findMin(Node<T>* node) {
while (node->left != nullptr) node = node->left;
return node;
}
// Recursive Function to search for a value in the tree
bool searchRecursive(Node<T>* current, T value) {
if (current == nullptr) return false;
if (current->data == value) return true;
return searchRecursive(current->left, value) || searchRecursive(current->right, value);
}
// Function for Recursive inorder traversal of the tree
void inorderRecursive(Node<T>* node) {
if (node != nullptr) {
inorderRecursive(node->left);
cout << node->data << " ";
inorderRecursive(node->right);
}
}
// Function for Recursive preorder traversal of the tree
void preorderRecursive(Node<T>* node) {
if (node != nullptr) {
cout << node->data << " ";
preorderRecursive(node->left);
preorderRecursive(node->right);
}
}
// Function for Recursive postorder traversal of the tree
void postorderRecursive(Node<T>* node) {
if (node != nullptr) {
postorderRecursive(node->left);
postorderRecursive(node->right);
cout << node->data << " ";
}
}
public:
// Constructor to initialize the tree
BinaryTree() : root(nullptr) {}
// Function to insert a node in the binary tree
void insertNode(T value) {
Node<T>* newNode = new Node<T>(value);
if (root == nullptr) {
root = newNode;
return;
}
queue<Node<T>*> q;
q.push(root);
while (!q.empty()) {
Node<T>* current = q.front();
q.pop();
if (current->left == nullptr) {
current->left = newNode;
return;
} else {
q.push(current->left);
}
if (current->right == nullptr) {
current->right = newNode;
return;
} else {
q.push(current->right);
}
}
}
// Function to delete a node from the tree
void deleteNode(T value) {
root = deleteRecursive(root, value);
}
// Function to search for a value in the tree
bool search(T value) {
return searchRecursive(root, value);
}
// Function to perform inorder traversal of the tree
void inorder() {
inorderRecursive(root);
cout << endl;
}
// Function to perform preorder traversal of the tree
void preorder() {
preorderRecursive(root);
cout << endl;
}
// Function to perform postorder traversal of the tree
void postorder() {
postorderRecursive(root);
cout << endl;
}
// Function to perform level order traversal of the tree
void levelOrder() {
if (root == nullptr) return;
queue<Node<T>*> q;
q.push(root);
while (!q.empty()) {
Node<T>* current = q.front();
q.pop();
cout << current->data << " ";
if (current->left != nullptr) q.push(current->left);
if (current->right != nullptr) q.push(current->right);
}
cout << endl;
}
};
int main() {
BinaryTree<int> tree;
// Insert the nodes into the tree
tree.insertNode(1);
tree.insertNode(2);
tree.insertNode(3);
tree.insertNode(4);
tree.insertNode(5);
tree.insertNode(6);
cout << "Inorder traversal: ";
tree.inorder();
cout << "Preorder traversal: ";
tree.preorder();
cout << "Postorder traversal: ";
tree.postorder();
cout << "Level order traversal: ";
tree.levelOrder();
cout << "Searching for 7: " << (tree.search(7) ? "Found" : "Not Found") << endl;
cout << "Searching for 6: " << (tree.search(6) ? "Found" : "Not Found") << endl;
tree.deleteNode(3);
cout << "Inorder traversal after removing 3: ";
tree.inorder();
return 0;
}
Output
Inorder traversal: 4 2 5 1 6 3
Preorder traversal: 1 2 4 5 3 6
Postorder traversal: 4 5 2 6 3 1
Level order traversal: 1 2 3 4 5 6
Searching for 7: Not Found
Searching for 6: Found
Inorder traversal after removing 3: 4 2 5 1 6 Basic Operations on Binary Tree in C++
Several operations can be performed on a binary tree to insert, delete, search, and traverse its nodes efficiently.
Insertion in Binary Tree
Insertion in a binary tree involves adding a new node at the first available position while maintaining the structure of the tree.
Approach
- Check whether the tree is empty
- If the tree is empty, create a new node and make it the root node
- Otherwise, perform a level order traversal using a queue
- Dequeue a node and check its left child
- If the left child is NULL, insert the new node as the left child
- Otherwise, check the right child
- If the right child is NULL, insert the new node as the right child
- If both children exist, enqueue them and continue the traversal
Deletion in Binary Tree
Deletion in a binary tree involves removing a node and rearranging the tree to maintain its structure.
Approach
- Find the node to be deleted using level order traversal
- Simultaneously identify the deepest node in the tree
- Replace the value of the node to be deleted with the value of the deepest node
- Locate the deepest node again using level order traversal
- Remove the deepest node from the tree
- If the node is a leaf node, it can be removed directly
Searching in Binary Tree
To search a given node in a binary tree, we need to traverse and compare each node with target node (node to be searched). Following is the algorithm to search a node in the binary tree:
Approach
- Check whether the tree is empty
- If the tree is empty, return
false - Perform a level order traversal using a queue
- Compare each node with the target value
- If a match is found, return
true - Enqueue the left and right children of the current node if they exist
- If all nodes are visited and no match is found, return
false
Traversals in Binary Tree
Traversal refers to the process of visiting every node of a binary tree in a specific order. Different traversal techniques are used depending on the order in which nodes need to be processed.
Common Traversal Techniques
- Inorder Traversal (Left -> Root -> Right): Visits the left subtree first, then the root node, and finally the right subtree
- Preorder Traversal (Root -> Left -> Right): Visits the root node first, followed by the left and right subtrees
- Postorder Traversal (Left -> Right -> Root): Visits both subtrees before processing the root node
- Level Order Traversal : Visits nodes level by level from top to bottom, moving from left to right within each level
Complexity Analysis of Basic Operations
The following table summarizes the time and space complexities of common binary tree operations.
Operation Name | Description | Time Complexity | Space Complexity |
|---|---|---|---|
Insertion | Inserts a new node into the binary tree. | O(N) | O(N) |
Deletion | Deletes a specific node from the binary tree. | O(N) | O(N) |
Searching | Searches for a specific value in the binary tree. | O(N) | O(N) |
Traversal | In-order, Pre-order, Post-order traversals | O(N) | O(N) |
Types of Binary Tree in C++
Binary trees can be classified into different types based on their structure, level completion, and node-value properties.
According to Number of Children
These types are classified based on the number of children associated with each node.
- Full Binary Tree: A full binary tree is a tree in which every node has either 0 or 2 children. In other words, all nodes except leaf nodes have two children.
- Degenerate Binary Tree: A degenerate binary tree is similar to a skewed binary tree. It's a tree where each parent node has only one child node.
- Skewed Binary Tree: A skewed binary tree is a tree in which all nodes have only one child, either left or right. There are two types: left-skewed and right-skewed.
According to Completion of Levels
These types are classified based on how completely the levels of the tree are filled.
- Complete Binary Tree: A complete binary tree is a binary tree in which all levels are completely filled except possibly the last level, which is filled from left to right.
- Perfect Binary Tree: A perfect binary tree is a binary tree in which all interior nodes have two children and all leaves are at the same level.
- Balanced Binary Tree: A balanced binary tree is a binary tree in which the height of the left and right subtrees of every node differs by at most one.
According to Node Values
These types are classified based on the ordering and organization of node values.
- Binary Search Tree: A Binary Search Tree is a binary tree in which all nodes in the left subtree are smaller than the root node and all nodes in the right subtree are greater.
- AVL Tree: An AVL tree is a self-balancing BST where the height of the left and right subtrees of any node differ by at most one.
- Red Black Tree: A Red-Black tree is a self-balancing BST where each node has an extra bit for denoting the color of the node, either red or black.
- B Tree: B-tree is a self-balancing tree data structure that maintains sorted data and allows searches, sequential access, insertions, and deletions in logarithmic time.
- B+ Tree: A B+ tree is a variant of the B-tree that has all data stored in the leaf nodes, while internal nodes only store keys.
- Segment Tree: A Segment Tree is a tree data structure used for storing information about intervals, or segments. It allows querying which of the stored segments contain a given point.
- Fenwick Tree: A Fenwick Tree is a data structure that can efficiently update elements and calculate prefix sums in a table of numbers.
Applications of Binary Tree
Binary trees are widely used in computer science for organizing hierarchical data and performing efficient search and processing operations.
- File System Organization: Used to represent hierarchical file and directory structures.
- Expression Trees: Used to represent and evaluate arithmetic and logical expressions.
- Huffman Coding Trees: Used in data compression algorithms to generate efficient binary codes.
- Binary Search Trees (BSTs): Used for efficient searching, insertion, and deletion of data.
- Decision Trees: Used in machine learning for classification and prediction tasks.
- Game Trees: Used in artificial intelligence to analyze possible game moves and outcomes.
- Syntax Trees: Used by compilers to represent the structure of source code.
- Database Indexing: Used in database systems to support efficient data retrieval and searching.
Related Articles
You can go through the following articles to improve your understanding about the binary tree data structure: