Vertical Order Traversal of Binary Tree in DSA C - Time & Space Complexity
We want to understand how the time needed to do vertical order traversal grows as the tree gets bigger.
Specifically, how does the number of nodes affect the work done?
Analyze the time complexity of the following code snippet.
// Simple vertical order traversal using BFS and map
void verticalOrderTraversal(Node* root) {
if (!root) return;
std::map> m;
std::queue> q;
q.push({root, 0});
while (!q.empty()) {
auto p = q.front(); q.pop();
Node* node = p.first;
int hd = p.second;
m[hd].push_back(node->data);
if (node->left) q.push({node->left, hd - 1});
if (node->right) q.push({node->right, hd + 1});
}
}
This code visits each node once using BFS, grouping nodes by horizontal distance (hd) using a map.
Note: std::map in C++ is a balanced BST, so each access/insert is O(log n).
Identify the loops, recursion, array traversals that repeat.
- BFS loop: Executes once per node (n times total).
- Per node work: Queue operations O(1), but
m[hd].push_back()takes O(log n) for map access + O(1) amortized push_back.
As the number of nodes (n) grows, BFS is O(n), but map operations dominate at O(n log n).
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 + 10*log(10) ≈ 40 (BFS + map ops) |
| 100 | About 100 + 100*log(100) ≈ 700 |
| 1000 | About 1000 + 1000*log(1000) ≈ 10,000 |
Pattern observation: The work grows as O(n log n) due to map operations.
Time Complexity: O(n log n)
BFS traversal: O(n). Map operations (n insertions/accesses): O(n log n). Total: O(n log n).
[X] Wrong: "Time complexity is O(n) since we visit each node once."
[OK] Correct: Ignores the O(log n) cost per map access/insertion. With n such operations, map contributes O(n log n).
Understanding this helps explain why data structures like maps affect complexity in tree traversals—common in interviews.
"What if we used a hash map (unordered_map) instead of a tree map? How would the time complexity change?"
(Hint: Average case O(1) per operation → total O(n))
Practice
Solution
Step 1: Understand vertical order traversal concept
Vertical order traversal groups nodes by their vertical columns, where the root is at column 0, left child at column -1, right child at column +1, and so on.Step 2: Compare with other traversal types
Depth levels group nodes horizontally, preorder and postorder are depth-first traversals, not vertical grouping.Final Answer:
Nodes grouped by their vertical columns from left to right -> Option AQuick Check:
Vertical order = vertical columns grouping [OK]
- Confusing vertical order with level order traversal
- Thinking preorder or postorder is vertical order
- Mixing horizontal levels with vertical columns
Solution
Step 1: Identify storage needs for vertical order traversal
We need to group nodes by their vertical column index, so a map (like HashMap or Dictionary) is used to store lists of nodes per column.Step 2: Understand role of other data structures
Queue is used for level order traversal but not for grouping columns; stack and linked list do not directly map columns to nodes.Final Answer:
HashMap or Dictionary -> Option BQuick Check:
Use map to group nodes by column [OK]
- Using stack instead of map for grouping
- Confusing queue usage for traversal with storage
- Not grouping nodes by column properly
1 / \ 2 3 / \ \ 4 5 6
Solution
Step 1: Assign vertical columns to each node
Root 1 is at column 0; 2 is at -1; 3 is at +1; 4 is at -2; 5 is at 0; 6 is at +2.Step 2: Group nodes by columns and read left to right
Column -2: [4], -1: [2], 0: [1,5], 1: [3], 2: [6]. Reading in order: 4, 2, 1, 5, 3, 6.Final Answer:
[4, 2, 1, 5, 3, 6] -> Option DQuick Check:
Group by columns left to right [OK]
- Mixing order of nodes in same column
- Ignoring multiple nodes in one column
- Reading nodes top-down instead of column-wise
void verticalOrder(Node* root) {
map nodes;
queue> q;
q.push({root, 0});
while (!q.empty()) {
auto p = q.front(); q.pop();
nodes[p.second].push_back(p.first->data);
if (p.first->left) q.push({p.first->left, p.second - 1});
if (p.first->right) q.push({p.first->right, p.second + 1});
}
for (auto it : nodes) {
for (int val : it.second) {
cout << val << " ";
}
}
}Solution
Step 1: Check initial queue push
The code pushes root to queue without checking if root is NULL, which can cause runtime error if tree is empty.Step 2: Verify other parts
Column indices are correctly updated; map usage is valid; sorting nodes inside columns is optional depending on problem.Final Answer:
Missing check if root is NULL before pushing to queue -> Option CQuick Check:
Always check root != NULL before queue push [OK]
- Ignoring NULL root causing crash
- Thinking map usage is incorrect
- Assuming sorting inside columns is mandatory
Solution
Step 1: Understand requirement to sort by row within columns
We need to track both column and row (depth) for each node to sort nodes vertically and then by depth.Step 2: Use map with pairs and sort
Store nodes in map keyed by column with vector of (row, value) pairs. Sort vector by row before printing to get correct order.Final Answer:
Store nodes in map<int, vector<pair<int,int>>> with (row, value) and sort by row before printing -> Option AQuick Check:
Track row and column, sort by row inside columns [OK]
- Not tracking row, so nodes unordered by depth
- Using stack breaks level order needed for row tracking
- Ignoring sorting inside columns
Ready to prove it?
Pass the test and this pattern moves unknown
