Loading W Code...
Hierarchical data structure - Binary Trees, BST, Traversals and more.
Unlike linear data structures (arrays, linked lists, stacks, queues) that organize values sequentially, a Tree is a non-linear hierarchical data structure. Think of a corporate organization chart: the CEO (root) sits at the top, branching down to Vice Presidents (parents), who supervise managers, down to individual contributors (leaves).
#include <iostream>
using namespace std;
// Basic Tree Node
struct TreeNode {
int data;
TreeNode* left;
TreeNode* right;
TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};
int main() {
// Create a simple binary tree
// 1
// / \
// 2 3
// / \
// 4 5
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);
cout << "Root: " << root->data << endl;
cout << "Left child: " << root->left->data << endl;
cout << "Right child: " << root->right->data << endl;
return 0;
}Trees are customized by placing rules on branching boundaries:
A tree where each node is restricted to a maximum of two children, called left and right child.
0 or 2 children.1.A binary tree configured with an ordering sorting property:
O(log n) on average. However, if the tree becomes skewed (like a linked list), complexity degrades to O(n).#include <iostream>
using namespace std;
struct TreeNode {
int data;
TreeNode* left;
TreeNode* right;
TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};
class BST {
public:
TreeNode* root;
BST() : root(nullptr) {}
// Insert into BST
TreeNode* insert(TreeNode* node, int val) {
if (node == nullptr) {
return new TreeNode(val);
}
if (val < node->data) {
node->left = insert(node->left, val);
} else {
node->right = insert(node->right, val);
}
return node;
}
void insert(int val) {
root = insert(root, val);
}
// Search in BST
bool search(TreeNode* node, int val) {
if (node == nullptr) return false;
if (node->data == val) return true;
if (val < node->data) {
return search(node->left, val);
} else {
return search(node->right, val);
}
}
bool search(int val) {
return search(root, val);
}
// Inorder traversal (gives sorted order for BST)
void inorder(TreeNode* node) {
if (node == nullptr) return;
inorder(node->left);
cout << node->data << " ";
inorder(node->right);
}
};
int main() {
BST tree;
tree.insert(50);
tree.insert(30);
tree.insert(70);
tree.insert(20);
tree.insert(40);
cout << "Inorder (sorted): ";
tree.inorder(tree.root);
cout << endl; // 20 30 40 50 70
cout << "Search 40: " << (tree.search(40) ? "Found" : "Not Found") << endl;
cout << "Search 100: " << (tree.search(100) ? "Found" : "Not Found") << endl;
return 0;
}Traversal is the process of visiting all nodes in a tree exactly once. Unlike linear data structures, trees can be traversed in multiple ways:
#include <iostream>
#include <queue>
using namespace std;
struct TreeNode {
int data;
TreeNode* left;
TreeNode* right;
TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};
// Inorder: Left -> Root -> Right
void inorder(TreeNode* node) {
if (node == nullptr) return;
inorder(node->left);
cout << node->data << " ";
inorder(node->right);
}
// Preorder: Root -> Left -> Right
void preorder(TreeNode* node) {
if (node == nullptr) return;
cout << node->data << " ";
preorder(node->left);
preorder(node->right);
}
// Postorder: Left -> Right -> Root
void postorder(TreeNode* node) {
if (node == nullptr) return;
postorder(node->left);
postorder(node->right);
cout << node->data << " ";
}
// Level Order (BFS)
void levelOrder(TreeNode* root) {
if (root == nullptr) return;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* node = q.front();
q.pop();
cout << node->data << " ";
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
int main() {
// 1
// / \
// 2 3
// / \
// 4 5
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);
cout << "Inorder: "; inorder(root); cout << endl; // 4 2 5 1 3
cout << "Preorder: "; preorder(root); cout << endl; // 1 2 4 5 3
cout << "Postorder: "; postorder(root); cout << endl; // 4 5 2 3 1
cout << "Level Order: "; levelOrder(root); cout << endl; // 1 2 3 4 5
return 0;
}Evaluating properties of tree structures is a common focal point in interviews:
O(n) Time)The height of a node is calculated recursively:
height = 1 + max(height(left), height(right))
-1 (or 0 depending on edge-count definition).O(n) Time)A tree is height-balanced if the left and right subtrees are balanced, and the height difference at the current node is at most 1. We can optimize this check by calculating height and balance status in a single recursive pass.
O(n) Time)The Diameter (or width) of a tree is the length of the longest path between any two nodes. The path may or may not pass through the root.
#include <iostream>
#include <algorithm>
using namespace std;
struct TreeNode {
int data;
TreeNode* left;
TreeNode* right;
TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};
// Height of tree
int height(TreeNode* node) {
if (node == nullptr) return -1; // or 0 depending on definition
int leftHeight = height(node->left);
int rightHeight = height(node->right);
return 1 + max(leftHeight, rightHeight);
}
// Check if balanced (height diff <= 1 for all nodes)
int checkBalance(TreeNode* node, bool& balanced) {
if (node == nullptr) return -1;
int leftH = checkBalance(node->left, balanced);
int rightH = checkBalance(node->right, balanced);
if (abs(leftH - rightH) > 1) {
balanced = false;
}
return 1 + max(leftH, rightH);
}
bool isBalanced(TreeNode* root) {
bool balanced = true;
checkBalance(root, balanced);
return balanced;
}
// Diameter of tree (optimized - O(n))
int diameterHelper(TreeNode* node, int& diameter) {
if (node == nullptr) return 0;
int leftH = diameterHelper(node->left, diameter);
int rightH = diameterHelper(node->right, diameter);
// Update diameter if path through this node is longer
diameter = max(diameter, leftH + rightH);
return 1 + max(leftH, rightH);
}
int diameter(TreeNode* root) {
int dia = 0;
diameterHelper(root, dia);
return dia;
}
int main() {
// 1
// / \
// 2 3
// / \
// 4 5
// /
// 6
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);
root->left->left->left = new TreeNode(6);
cout << "Height: " << height(root) << endl; // 3
cout << "Balanced: " << (isBalanced(root) ? "Yes" : "No") << endl; // No
cout << "Diameter: " << diameter(root) << endl; // 4 (path: 6-4-2-5 or 6-4-2-1-3)
return 0;
}