Tree Data Structure
- Published on 🕒 4 min read
- Authors

- Name
- Mohammad Mustakim Hassan
- @mmhshayer
Introduction
A tree is a hierarchical data structure that consists of nodes connected by edges. It is composed of a root node and zero or more subtrees, where each subtree itself is a tree. Trees are widely used for representing hierarchical relationships and organizing data in a hierarchical manner.
Operations
Trees support various operations, including:
- Insertion: Adding nodes to the tree.
- Deletion: Removing nodes from the tree.
- Traversal: Visiting all nodes of the tree in a specific order.
- Search: Finding nodes with a specific value or key in the tree.
- Height Calculation: Calculating the height of the tree.
- Balancing: Balancing the tree to maintain optimal performance.
Advantage
- Hierarchical Organization: Trees provide a hierarchical organization of data, making them suitable for representing relationships such as parent-child, ancestor-descendant, and containment.
- Efficient Searching: Trees offer efficient searching operations, with average-case time complexities often better than linear search, especially in balanced trees like binary search trees.
- Ordered Access: Trees can maintain elements in sorted order, facilitating efficient traversal and search operations, which is essential in applications requiring ordered data retrieval.
Disadvantage
- Complexity: Tree operations can be more complex than linear data structures, requiring careful handling of insertion, deletion, and traversal, especially in balanced or self-adjusting trees.
- Memory Overhead: Trees may consume more memory compared to linear data structures, especially in balanced trees, due to additional pointers or metadata required for maintaining the tree structure.
- Balancing Overhead: Maintaining balance in self-adjusting trees like AVL trees or red-black trees may incur additional overhead in terms of computational complexity and memory usage.
Application
Trees find applications in various scenarios, including:
- File Systems: Organizing files and directories in file systems using hierarchical tree structures, facilitating efficient file retrieval and management.
- Database Indexing: Implementing indexing structures like B-trees and binary search trees in databases for efficient data retrieval and query processing.
- Syntax Trees: Representing the syntactic structure of programs or expressions in compilers and interpreters using abstract syntax trees (ASTs) for parsing and analysis.
- Hierarchical Data Representation: Storing and managing hierarchical data such as organizational charts, XML/JSON documents, and network routing tables using tree structures.
Example JavaScript Implementation & Operations demonstration
class TreeNode {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor() {
this.root = null;
}
insert(value) {
const newNode = new TreeNode(value);
if (!this.root) {
this.root = newNode;
return;
}
let current = this.root;
while (true) {
if (value < current.value) {
if (!current.left) {
current.left = newNode;
return;
}
current = current.left;
} else if (value > current.value) {
if (!current.right) {
current.right = newNode;
return;
}
current = current.right;
} else {
return; // Do not allow duplicate values
}
}
}
search(value) {
let current = this.root;
while (current) {
if (value === current.value) {
return true;
} else if (value < current.value) {
current = current.left;
} else {
current = current.right;
}
}
return false;
}
getHeight(node) {
if (!node) return 0;
const leftHeight = this.getHeight(node.left);
const rightHeight = this.getHeight(node.right);
return Math.max(leftHeight, rightHeight) + 1;
}
delete(value) {
this.root = this._deleteNode(this.root, value);
}
_deleteNode(node, value) {
if (!node) {
return null;
}
if (value < node.value) {
node.left = this._deleteNode(node.left, value);
} else if (value > node.value) {
node.right = this._deleteNode(node.right, value);
} else {
if (!node.left && !node.right) {
return null;
}
if (!node.left) {
return node.right;
}
if (!node.right) {
return node.left;
}
const minRightNode = this._findMinNode(node.right);
node.value = minRightNode.value;
node.right = this._deleteNode(node.right, minRightNode.value);
}
return node;
}
_findMinNode(node) {
while (node.left) {
node = node.left;
}
return node;
}
inOrderTraversal(node, callback) {
if (node) {
this.inOrderTraversal(node.left, callback);
callback(node.value);
this.inOrderTraversal(node.right, callback);
}
}
balance() {
const sortedValues = [];
this.inOrderTraversal(this.root, (value) => {
sortedValues.push(value);
});
this.root = this._buildBalancedBST(sortedValues, 0, sortedValues.length - 1);
}
_buildBalancedBST(sortedValues, start, end) {
if (start > end) {
return null;
}
const mid = Math.floor((start + end) / 2);
const newNode = new TreeNode(sortedValues[mid]);
newNode.left = this._buildBalancedBST(sortedValues, start, mid - 1);
newNode.right = this._buildBalancedBST(sortedValues, mid + 1, end);
return newNode;
}
}
// Example usage
const bst = new BinarySearchTree();
// Insertion
bst.insert(10);
bst.insert(5);
bst.insert(15);
bst.insert(3);
bst.insert(7);
bst.insert(12);
bst.insert(20);
// Search
const found = bst.search(10); // Output: true
// Height Calculation
const height = bst.getHeight(bst.root); // Output: 3
// Deletion
bst.delete(15);
// Traversal
bst.inOrderTraversal(bst.root, (value) => {
console.log(value); // Output: 3, 5, 7, 10, 12, 20 (in-order traversal)
});
// Balancing
bst.balance();