Trees: Terminology, Traversals & Representation
Tree — পরিভাষা, ট্রাভার্সাল
1. Why Trees? (গাছ কেন?)
Up to now we have studied linear structures — arrays, linked lists, stacks, queues. They are good when data flows in a straight line. But the real world is rarely linear: a file system has folders inside folders, an HTML document has tags inside tags, a Bangladeshi family has parents and children and grandchildren. To model this we need a structure that branches. That structure is a tree.
2. Vocabulary You Must Memorise (পরিভাষা)
| Term | Meaning | বাংলায় |
|---|---|---|
| Root | The topmost node — has no parent. | সবচেয়ে উপরের node, যার কোনো parent নেই। |
| Parent / Child | A direct ancestor / descendant by one edge. | একটি edge দূরত্বের সরাসরি পূর্বপুরুষ / উত্তরসূরি। |
| Sibling | Nodes sharing the same parent. | একই parent-এর সন্তানরা — ভাই-বোন। |
| Leaf | A node with no children. | যার কোনো সন্তান নেই — পাতা। |
| Internal node | A node with at least one child. | অন্তত একটি সন্তান আছে এমন node। |
| Depth of node | Edges from root to that node. | root থেকে ওই node পর্যন্ত edge সংখ্যা। |
| Height of tree | Maximum depth among all nodes. | সব node-এর মধ্যে সর্বোচ্চ depth। |
| Subtree | A node together with all its descendants. | একটি node ও তার সব উত্তরসূরি মিলিয়ে। |
| Binary tree | Each node has at most 2 children (left, right). | প্রতিটি node-এর সর্বোচ্চ ২টি সন্তান। |
3. A Picture Worth 1000 Lines
Here is a binary tree of depth 3. Below the picture, look at how each traversal "walks" the same tree differently.
4. Representation — Pointers vs Array
There are two common ways to store a tree in memory.
✅ Pointer-based (সাধারণ পদ্ধতি)
- Each node is a
structwithleft,rightpointers. - Easy to insert / delete arbitrary nodes.
- Memory used = O(n).
- Used in BST, AVL, RB, expression trees.
⚙️ Array-based (implicit tree)
- For node at index
i: left =2i+1, right =2i+2, parent =(i−1)/2. - Used in heaps and segment trees.
- Wastes space if tree is sparse / unbalanced.
- No pointer overhead, very cache-friendly.
if (!root) return; রাখুন।
5. Build a Tree & Recursive Traversals — Live
Below we build the tree from Figure 16.1, then run all three depth-first traversals using simple recursion.
#include <bits/stdc++.h>
using namespace std;
// একটি node — value আর দুটি child pointer।
struct Node {
int val;
Node *left, *right;
Node(int v) : val(v), left(nullptr), right(nullptr) {}
};
void preorder(Node* r) {
if (!r) return;
cout << r->val << ' ';
preorder(r->left);
preorder(r->right);
}
void inorder(Node* r) {
if (!r) return;
inorder(r->left);
cout << r->val << ' ';
inorder(r->right);
}
void postorder(Node* r) {
if (!r) return;
postorder(r->left);
postorder(r->right);
cout << r->val << ' ';
}
int main() {
Node* root = new Node(1);
root->left = new Node(2);
root->right = new Node(3);
root->left->left = new Node(4);
root->left->right = new Node(5);
root->right->left = new Node(6);
root->right->right = new Node(7);
root->left->left->left = new Node(8);
root->left->left->right = new Node(9);
cout << "Pre : "; preorder(root); cout << '\n';
cout << "In : "; inorder(root); cout << '\n';
cout << "Post : "; postorder(root); cout << '\n';
return 0;
}
6. Level-Order Traversal — BFS with a Queue
Depth-first traversals naturally use recursion (a stack). Level-order goes level-by-level — that needs
a queue. This is also called BFS on a tree and is the foundation of "shortest-path" thinking that
you will see again with Dijkstra in Phase 6.
#include <bits/stdc++.h>
using namespace std;
struct Node { int v; Node *l,*r; Node(int x):v(x),l(nullptr),r(nullptr){} };
void levelOrder(Node* root) {
if (!root) return;
queue<Node*> q;
q.push(root);
int level = 0;
while (!q.empty()) {
int sz = q.size();
cout << "Level " << level++ << ": ";
while (sz--) {
Node* n = q.front(); q.pop();
cout << n->v << ' ';
if (n->l) q.push(n->l);
if (n->r) q.push(n->r);
}
cout << '\n';
}
}
int main() {
Node* root = new Node(1);
root->l = new Node(2);
root->r = new Node(3);
root->l->l = new Node(4);
root->l->r = new Node(5);
root->r->r = new Node(7);
levelOrder(root);
return 0;
}
7. A Tiny Proof — Why edges = n − 1
Proof (induction). Base: n = 1, no edges, 1 − 1 = 0. ✓ Inductive step: assume any tree with k nodes has k − 1 edges. Add a new leaf; that adds exactly one new edge connecting it to its parent. So (k + 1) nodes have k edges = (k + 1) − 1. ∎
8. Common Bugs to Avoid
recursion-এ
!root check ভুললে SIGSEGV।delete না করলে heap বড় হতে থাকে — competitive-এ সমস্যা না, প্রোডাকশন-এ মারাত্মক।10⁵ গভীরতার skewed tree-তে recursion crash করতে পারে — iterative করুন।
ছোট/বড় বা west/east — যেকোনো একটি নিয়ম মানুন consistently।
9. Practice Problems
প্রতিটি প্রশ্নে runnable C++ answer দেওয়া হয়েছে। আগে নিজে চেষ্টা করুন।
-
Write a function that returns the height of a binary tree.একটি binary tree-এর height return করুন।
✨ Show Answer
height.cpp#include <bits/stdc++.h> using namespace std; struct N{int v;N*l,*r;N(int x):v(x),l(nullptr),r(nullptr){}}; int height(N* r){ return r? 1+max(height(r->l),height(r->r)) : 0; } int main(){ N* r=new N(1); r->l=new N(2); r->r=new N(3); r->l->l=new N(4); cout << "Height = " << height(r); }Height বলতে এখানে node-সংখ্যা ধরা হয়েছে (অনেক বইয়ে edge-সংখ্যা ধরা হয় — দুটিই বৈধ, প্রশ্ন বুঝে ব্যবহার করুন)।
-
Count total nodes and number of leaves in a binary tree.মোট node ও leaf-এর সংখ্যা গুনুন।
✨ Show Answer
count.cpp#include <bits/stdc++.h> using namespace std; struct N{int v;N*l,*r;N(int x):v(x),l(nullptr),r(nullptr){}}; int cntNodes(N* r){ return r? 1+cntNodes(r->l)+cntNodes(r->r) : 0; } int cntLeaves(N* r){ if(!r) return 0; if(!r->l && !r->r) return 1; return cntLeaves(r->l)+cntLeaves(r->r); } int main(){ N* r=new N(1); r->l=new N(2); r->r=new N(3); r->l->l=new N(4); r->l->r=new N(5); cout << "Nodes=" << cntNodes(r) << " Leaves=" << cntLeaves(r); } -
Check whether a binary tree is height-balanced (|left height − right height| ≤ 1 for every node).প্রতিটি node-এ left ও right height-এর পার্থক্য ≤ 1 কিনা পরীক্ষা করুন।
✨ Show Answer
balanced.cpp#include <bits/stdc++.h> using namespace std; struct N{int v;N*l,*r;N(int x):v(x),l(nullptr),r(nullptr){}}; // returns height; sets bal=false if unbalanced anywhere int chk(N* r, bool& bal){ if(!r) return 0; int a=chk(r->l,bal), b=chk(r->r,bal); if(abs(a-b)>1) bal=false; return 1+max(a,b); } int main(){ N* r=new N(1); r->l=new N(2); r->l->l=new N(3); bool b=true; chk(r,b); cout << (b? "Balanced" : "NOT balanced"); } -
Mirror (invert) a binary tree.একটি binary tree-এর mirror তৈরি করুন।
✨ Show Answer
mirror.cpp#include <bits/stdc++.h> using namespace std; struct N{int v;N*l,*r;N(int x):v(x),l(nullptr),r(nullptr){}}; void mirror(N* r){ if(!r) return; swap(r->l,r->r); mirror(r->l); mirror(r->r); } void in(N* r){ if(!r)return; in(r->l); cout<<r->v<<' '; in(r->r); } int main(){ N* r=new N(1); r->l=new N(2); r->r=new N(3); r->l->l=new N(4); cout << "Before: "; in(r); cout << '\n'; mirror(r); cout << "After : "; in(r); } -
Print level-order in a zig-zag pattern (left→right, then right→left, alternating).Zig-zag level order — এক level বাঁ থেকে ডান, পরের level ডান থেকে বাঁ।
✨ Show Answer
zigzag.cpp#include <bits/stdc++.h> using namespace std; struct N{int v;N*l,*r;N(int x):v(x),l(nullptr),r(nullptr){}}; void zz(N* root){ if(!root) return; deque<N*> dq; dq.push_back(root); bool ltr=true; while(!dq.empty()){ int sz=dq.size(); while(sz--){ if(ltr){ N* n=dq.front(); dq.pop_front(); cout<<n->v<<' '; if(n->l) dq.push_back(n->l); if(n->r) dq.push_back(n->r); } else { N* n=dq.back(); dq.pop_back(); cout<<n->v<<' '; if(n->r) dq.push_front(n->r); if(n->l) dq.push_front(n->l); } } cout<<'\n'; ltr=!ltr; } } int main(){ N* r=new N(1); r->l=new N(2); r->r=new N(3); r->l->l=new N(4); r->l->r=new N(5); r->r->l=new N(6); r->r->r=new N(7); zz(r); } -
Iterative inorder traversal using an explicit stack.Recursion ছাড়া, explicit stack দিয়ে inorder।
✨ Show Answer
iter_in.cpp#include <bits/stdc++.h> using namespace std; struct N{int v;N*l,*r;N(int x):v(x),l(nullptr),r(nullptr){}}; void iterIn(N* root){ stack<N*> st; N* cur=root; while(cur || !st.empty()){ while(cur){ st.push(cur); cur=cur->l; } cur=st.top(); st.pop(); cout<<cur->v<<' '; cur=cur->r; } } int main(){ N* r=new N(4); r->l=new N(2); r->r=new N(6); r->l->l=new N(1); r->l->r=new N(3); iterIn(r); } -
Serialize and deserialize a binary tree using pre-order with NULL markers.Pre-order ও NULL marker দিয়ে serialize/deserialize করুন।
✨ Show Answer
serialize.cpp#include <bits/stdc++.h> using namespace std; struct N{int v;N*l,*r;N(int x):v(x),l(nullptr),r(nullptr){}}; void ser(N* r, string& s){ if(!r){ s+="# "; return; } s+=to_string(r->v)+' '; ser(r->l,s); ser(r->r,s); } N* des(stringstream& ss){ string t; if(!(ss>>t)) return nullptr; if(t=="#") return nullptr; N* n=new N(stoi(t)); n->l=des(ss); n->r=des(ss); return n; } void in(N* r){ if(!r)return; in(r->l); cout<<r->v<<' '; in(r->r); } int main(){ N* r=new N(1); r->l=new N(2); r->r=new N(3); r->r->l=new N(4); string s; ser(r,s); cout << "Serial: " << s << '\n'; stringstream ss(s); N* r2=des(ss); cout << "Inorder of rebuilt: "; in(r2); }
Summary — Module 16
A tree is a connected, acyclic structure with n nodes and n − 1 edges. Four traversals (pre/in/post/level) capture different orderings of the same nodes. Pointer-based representation is flexible; array-based is cache-friendly and used in heaps. Recursive traversals are concise but vulnerable to stack overflow on deep skewed trees — keep an iterative version in your toolkit.