|
| 1 | +<h1 align='center'>Vertical - Tree - Traversal</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [Vertical Tree Traversal](https://www.geeksforgeeks.org/problems/print-a-binary-tree-in-vertical-order/1) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | + |
| 11 | + |
| 12 | +## Problem Explanation |
| 13 | + |
| 14 | +The objective of vertical tree traversal is to print the nodes of a binary tree in vertical order. In this traversal: |
| 15 | +- Nodes are printed vertically, from top to bottom. |
| 16 | +- Nodes that are on the same vertical line are printed together. |
| 17 | +- The vertical lines are defined based on the horizontal distance from the root node. |
| 18 | + |
| 19 | +### Vertical Line Definition |
| 20 | +- Assign a horizontal distance (HD) to each node: |
| 21 | + - The HD of the root node is `0`. |
| 22 | + - For the left child, HD is `HD of parent - 1`. |
| 23 | + - For the right child, HD is `HD of parent + 1`. |
| 24 | + |
| 25 | +### Example |
| 26 | +Consider the following binary tree: |
| 27 | + |
| 28 | +``` |
| 29 | + 1 |
| 30 | + / \ |
| 31 | + 2 3 |
| 32 | + / \ \ |
| 33 | + 4 5 6 |
| 34 | + / |
| 35 | + 7 |
| 36 | +``` |
| 37 | + |
| 38 | +**Vertical Order Output**: |
| 39 | +- Vertical lines: |
| 40 | + - HD -2: `4` |
| 41 | + - HD -1: `2` |
| 42 | + - HD 0: `1, 5, 7` |
| 43 | + - HD 1: `3` |
| 44 | + - HD 2: `6` |
| 45 | + |
| 46 | +So the output will be: |
| 47 | +``` |
| 48 | +4 |
| 49 | +2 |
| 50 | +1 |
| 51 | +5 |
| 52 | +7 |
| 53 | +3 |
| 54 | +6 |
| 55 | +``` |
| 56 | + |
| 57 | +## Step 2: Approach |
| 58 | + |
| 59 | +### Approach Explanation |
| 60 | +1. **Mapping HD**: Use a data structure (like a map) to map each HD to a list of nodes that fall under that HD. |
| 61 | +2. **Traversal**: Perform a level-order traversal (BFS or DFS) of the tree, updating the HD for each node: |
| 62 | + - For each node, add its value to the list corresponding to its HD in the map. |
| 63 | + - Recursively traverse the left child with `HD - 1` and the right child with `HD + 1`. |
| 64 | +3. **Output**: After collecting nodes in the map, output them in order of HD, from the smallest to the largest. |
| 65 | + |
| 66 | +### Beginner-Friendly Steps |
| 67 | +1. Initialize a map to store nodes against their HDs. |
| 68 | +2. Start from the root node, initializing its HD to `0`. |
| 69 | +3. For each node, add its value to the corresponding list in the map. |
| 70 | +4. Traverse left and right children, adjusting the HD accordingly. |
| 71 | +5. Finally, iterate through the sorted keys of the map to print the node values. |
| 72 | + |
| 73 | +## Problem Solution |
| 74 | +```cpp |
| 75 | +#include <map> |
| 76 | +#include <vector> |
| 77 | +#include <queue> |
| 78 | +using namespace std; |
| 79 | + |
| 80 | +struct Node { |
| 81 | + int data; |
| 82 | + Node *left, *right; |
| 83 | +}; |
| 84 | + |
| 85 | +class Solution { |
| 86 | +public: |
| 87 | + void verticalOrder(Node* root) { |
| 88 | + if (root == NULL) return; |
| 89 | + |
| 90 | + // Map to store nodes in vertical order |
| 91 | + map<int, vector<int>> verticalMap; |
| 92 | + |
| 93 | + // Queue for BFS traversal with horizontal distance |
| 94 | + queue<pair<Node*, int>> q; |
| 95 | + q.push({root, 0}); // {node, horizontal distance} |
| 96 | + |
| 97 | + while (!q.empty()) { |
| 98 | + auto [node, hd] = q.front(); // Get the front element |
| 99 | + q.pop(); |
| 100 | + |
| 101 | + // Store node data in the map according to horizontal distance |
| 102 | + verticalMap[hd].push_back(node->data); |
| 103 | + |
| 104 | + // Push left child with HD - 1 |
| 105 | + if (node->left) q.push({node->left, hd - 1}); |
| 106 | + // Push right child with HD + 1 |
| 107 | + if (node->right) q.push({node->right, hd + 1}); |
| 108 | + } |
| 109 | + |
| 110 | + // Output the vertical order |
| 111 | + for (const auto& pair : verticalMap) { |
| 112 | + for (int value : pair.second) { |
| 113 | + cout << value << " "; |
| 114 | + } |
| 115 | + cout << endl; // Newline for different verticals |
| 116 | + } |
| 117 | + } |
| 118 | +}; |
| 119 | +``` |
| 120 | + |
| 121 | +## Problem Solution Explanation |
| 122 | + |
| 123 | +1. **Include Libraries** |
| 124 | + ```cpp |
| 125 | + #include <map> |
| 126 | + #include <vector> |
| 127 | + #include <queue> |
| 128 | + ``` |
| 129 | + - These lines include the necessary libraries: |
| 130 | + - `<map>`: For using the map data structure to store vertical nodes. |
| 131 | + - `<vector>`: For storing multiple values (nodes) corresponding to each vertical. |
| 132 | + - `<queue>`: For implementing the BFS (Breadth-First Search) traversal. |
| 133 | + |
| 134 | +2. **Node Structure Definition** |
| 135 | + ```cpp |
| 136 | + struct Node { |
| 137 | + int data; |
| 138 | + Node *left, *right; |
| 139 | + }; |
| 140 | + ``` |
| 141 | + - This defines a `Node` structure to represent a binary tree node: |
| 142 | + - `data`: An integer storing the value of the node. |
| 143 | + - `left`: A pointer to the left child node. |
| 144 | + - `right`: A pointer to the right child node. |
| 145 | +
|
| 146 | +3. **Class Definition** |
| 147 | + ```cpp |
| 148 | + class Solution { |
| 149 | + public: |
| 150 | + ``` |
| 151 | + - Defines the `Solution` class, which contains methods to solve the problem. The `public` access specifier indicates that the members of this class can be accessed from outside the class. |
| 152 | + |
| 153 | +4. **Vertical Order Method Declaration** |
| 154 | + ```cpp |
| 155 | + void verticalOrder(Node* root) { |
| 156 | + ``` |
| 157 | + - Declares the `verticalOrder` method that takes a pointer to the root of the binary tree as an argument. |
| 158 | +
|
| 159 | +5. **Check for Empty Tree** |
| 160 | + ```cpp |
| 161 | + if (root == NULL) return; |
| 162 | + ``` |
| 163 | + - This line checks if the root node is `NULL`. If it is, the function immediately returns, as there are no nodes to process. |
| 164 | + |
| 165 | +6. **Map Initialization** |
| 166 | + ```cpp |
| 167 | + map<int, vector<int>> verticalMap; |
| 168 | + ``` |
| 169 | + - Initializes a map called `verticalMap` where: |
| 170 | + - The key is an integer (the horizontal distance from the root). |
| 171 | + - The value is a vector of integers (the node values at that horizontal distance). |
| 172 | + |
| 173 | +7. **Queue Initialization for BFS** |
| 174 | + ```cpp |
| 175 | + queue<pair<Node*, int>> q; |
| 176 | + q.push({root, 0}); // {node, horizontal distance} |
| 177 | + ``` |
| 178 | + - Declares a queue named `q` to facilitate level-order traversal. Each element in the queue is a pair consisting of: |
| 179 | + - A pointer to the node (`Node*`). |
| 180 | + - An integer representing the horizontal distance (HD) of that node. |
| 181 | + - Pushes the root node into the queue with an HD of `0`. |
| 182 | +
|
| 183 | +8. **BFS Loop** |
| 184 | + ```cpp |
| 185 | + while (!q.empty()) { |
| 186 | + ``` |
| 187 | + - Starts a loop that continues as long as the queue is not empty, indicating there are still nodes to process. |
| 188 | + |
| 189 | +9. **Extract Node and HD** |
| 190 | + ```cpp |
| 191 | + auto [node, hd] = q.front(); // Get the front element |
| 192 | + q.pop(); |
| 193 | + ``` |
| 194 | + - Uses structured bindings (C++17 feature) to unpack the front element of the queue into `node` and `hd`. |
| 195 | + - `q.front()` retrieves the element at the front of the queue without removing it. |
| 196 | + - `q.pop()` removes the front element from the queue after retrieving it. |
| 197 | + |
| 198 | +10. **Store Node Data in Map** |
| 199 | + ```cpp |
| 200 | + verticalMap[hd].push_back(node->data); |
| 201 | + ``` |
| 202 | + - This line adds the current node's data to the vector in `verticalMap` that corresponds to its horizontal distance (`hd`). |
| 203 | +
|
| 204 | +11. **Push Left Child into Queue** |
| 205 | + ```cpp |
| 206 | + if (node->left) q.push({node->left, hd - 1}); |
| 207 | + ``` |
| 208 | + - If the current node has a left child, it is pushed into the queue with an HD of `hd - 1` (since left children are one unit closer to the left). |
| 209 | +
|
| 210 | +12. **Push Right Child into Queue** |
| 211 | + ```cpp |
| 212 | + if (node->right) q.push({node->right, hd + 1}); |
| 213 | + ``` |
| 214 | + - If the current node has a right child, it is pushed into the queue with an HD of `hd + 1` (since right children are one unit closer to the right). |
| 215 | +
|
| 216 | +13. **Output Vertical Order** |
| 217 | + ```cpp |
| 218 | + for (const auto& pair : verticalMap) { |
| 219 | + ``` |
| 220 | + - This loop iterates through each key-value pair in the `verticalMap`. |
| 221 | +
|
| 222 | +14. **Print Node Values for Each Vertical** |
| 223 | + ```cpp |
| 224 | + for (int value : pair.second) { |
| 225 | + cout << value << " "; |
| 226 | + } |
| 227 | + cout << endl; // Newline for different verticals |
| 228 | + ``` |
| 229 | + - The inner loop iterates through the vector of node values (`pair.second`) corresponding to each HD and prints each value followed by a space. |
| 230 | + - After printing all values for a vertical line, it outputs a newline for better readability. |
| 231 | +
|
| 232 | +
|
| 233 | +## Step 4: Output Examples with Explanation |
| 234 | +
|
| 235 | +### Example 1 |
| 236 | +Given the tree: |
| 237 | +``` |
| 238 | + 1 |
| 239 | + / \ |
| 240 | + 2 3 |
| 241 | + / \ \ |
| 242 | + 4 5 6 |
| 243 | + / |
| 244 | + 7 |
| 245 | +``` |
| 246 | +
|
| 247 | +**Output**: |
| 248 | +``` |
| 249 | +4 |
| 250 | +2 |
| 251 | +1 5 7 |
| 252 | +3 |
| 253 | +6 |
| 254 | +``` |
| 255 | +
|
| 256 | +### Explanation |
| 257 | +- The first vertical (HD -2) contains node `4`. |
| 258 | +- The second vertical (HD -1) contains node `2`. |
| 259 | +- The third vertical (HD 0) contains nodes `1`, `5`, and `7` printed together. |
| 260 | +- The fourth vertical (HD 1) contains node `3`. |
| 261 | +- The fifth vertical (HD 2) contains node `6`. |
| 262 | +
|
| 263 | +### Example 2 |
| 264 | +For a single node tree: |
| 265 | +``` |
| 266 | + 1 |
| 267 | +``` |
| 268 | +
|
| 269 | +**Output**: |
| 270 | +``` |
| 271 | +1 |
| 272 | +``` |
| 273 | +
|
| 274 | +### Explanation |
| 275 | +- The tree consists only of the root node, which is also the only node at HD `0`. |
| 276 | +
|
| 277 | +## Step 5: Time and Space Complexity |
| 278 | +
|
| 279 | +### Time Complexity |
| 280 | +- The algorithm performs a level-order traversal (BFS) of the binary tree: |
| 281 | + - Each node is visited once. |
| 282 | + - Therefore, the time complexity is **O(n)**, where `n` is the number of nodes in the tree. |
| 283 | +
|
| 284 | +### Space Complexity |
| 285 | +- The space complexity is determined by: |
| 286 | + - The queue used for BFS: In the worst case (a balanced tree), it can hold up to `O(w)` nodes, where `w` is the maximum width of the tree. |
| 287 | + - The map that stores vertical values: In the worst case, it can also hold `O(n)` nodes if every node is in a different vertical. |
| 288 | +
|
| 289 | +Thus, the space complexity is **O(n)** in the worst case due to storing nodes in the map. |
| 290 | +
|
| 291 | +### Summary |
| 292 | +- **Time Complexity**: **O(n)** |
| 293 | +- **Space Complexity**: **O(n)** |
| 294 | +
|
| 295 | +This thorough explanation covers the vertical tree traversal problem from understanding the problem statement to implementation and analysis of the code. If you have any questions or need further clarification, feel free to ask! |
0 commit comments