|
| 1 | +<h1 align='center'>BST - To - Max - Heap</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [BST to Max Heap](https://www.geeksforgeeks.org/problems/bst-to-max-heap/1?itm_source=geeksforgeeks&itm_medium=article&itm_campaign=practice_card) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | +## Problem Explanation |
| 11 | + |
| 12 | +The problem requires us to **convert a Binary Search Tree (BST)** into a **Max Heap** while maintaining the property that in the resulting Max Heap: |
| 13 | +1. The value of each parent node must be greater than or equal to the values of its children (Max Heap Property). |
| 14 | +2. The values in the left subtree must be less than those in the right subtree for every node in the tree. |
| 15 | + |
| 16 | +**Explanation:** |
| 17 | +- A **Binary Search Tree (BST)** is a binary tree where for every node: |
| 18 | + - The left child is smaller than the parent node. |
| 19 | + - The right child is greater than the parent node. |
| 20 | + |
| 21 | +- A **Max Heap** is a binary tree where the value of each node is greater than or equal to the values of its children, and the tree is complete (i.e., all levels are filled except possibly the last one, which is filled from left to right). |
| 22 | + |
| 23 | +The task is to take a given BST and convert it into a Max Heap while satisfying the special condition that all values in the left subtree of a node should be less than all values in the right subtree. After converting the tree to a Max Heap, we need to perform a post-order traversal of the tree and return the result. |
| 24 | + |
| 25 | +**Example:** |
| 26 | + |
| 27 | +Given the following BST: |
| 28 | + |
| 29 | +``` |
| 30 | + 4 |
| 31 | + / \ |
| 32 | + 2 6 |
| 33 | + / \ / \ |
| 34 | + 1 3 5 7 |
| 35 | +``` |
| 36 | + |
| 37 | +We need to transform it into a Max Heap where the largest element goes to the root, and the tree is arranged such that: |
| 38 | +1. All left child nodes are less than the right child nodes. |
| 39 | +2. The Max Heap property is maintained. |
| 40 | + |
| 41 | +After conversion, the tree will look like this: |
| 42 | + |
| 43 | +``` |
| 44 | + 7 |
| 45 | + / \ |
| 46 | + 3 6 |
| 47 | + / \ / \ |
| 48 | + 1 2 4 5 |
| 49 | +``` |
| 50 | + |
| 51 | +The post-order traversal of this tree is: **1 2 3 4 5 6 7**. |
| 52 | + |
| 53 | +## Problem Solution |
| 54 | +```cpp |
| 55 | +class Solution{ |
| 56 | + public: |
| 57 | + void inOrder(Node* root, vector<int> &nodes){ |
| 58 | + if(root == NULL) return; |
| 59 | + |
| 60 | + inOrder(root -> left, nodes); |
| 61 | + nodes.push_back(root -> data); |
| 62 | + inOrder(root -> right, nodes); |
| 63 | + } |
| 64 | + |
| 65 | + void inOrderToHeap(Node* root, vector<int> &nodes, int & index){ |
| 66 | + if(root == NULL) return; |
| 67 | + |
| 68 | + inOrderToHeap(root -> left, nodes, index); |
| 69 | + inOrderToHeap(root -> right, nodes, index); |
| 70 | + |
| 71 | + root -> data = nodes[index++]; |
| 72 | + } |
| 73 | + |
| 74 | + void convertToMaxHeapUtil(Node* root) |
| 75 | + { |
| 76 | + vector<int> nodes; |
| 77 | + inOrder(root, nodes); |
| 78 | + |
| 79 | + int index = 0; |
| 80 | + inOrderToHeap(root, nodes, index); |
| 81 | + } |
| 82 | +}; |
| 83 | +``` |
| 84 | + |
| 85 | +## Problem Solution Explanation |
| 86 | + |
| 87 | +```cpp |
| 88 | +class Solution{ |
| 89 | +public: |
| 90 | + // Step 1: In-order traversal to collect node values |
| 91 | + void inOrder(Node* root, vector<int> &nodes){ |
| 92 | + if(root == NULL) return; // Base case: if the node is null, return |
| 93 | + |
| 94 | + inOrder(root -> left, nodes); // Recurse on the left subtree |
| 95 | + nodes.push_back(root -> data); // Store the current node's value |
| 96 | + inOrder(root -> right, nodes); // Recurse on the right subtree |
| 97 | + } |
| 98 | +``` |
| 99 | + |
| 100 | +#### Explanation: |
| 101 | + |
| 102 | +1. **Function Definition (`inOrder`)**: |
| 103 | + - The function `inOrder(Node* root, vector<int> &nodes)` performs an **in-order traversal** of the binary tree (BST) starting at the root. |
| 104 | + - It takes the `root` node of the tree and a reference to a vector `nodes` which will store the values of the tree in ascending order. |
| 105 | + |
| 106 | +2. **Base Case (`if(root == NULL) return;`)**: |
| 107 | + - If the current node is `NULL`, this means we've reached the end of a branch, and there’s no further processing required. So, the function returns. |
| 108 | + |
| 109 | +3. **Recursion (`inOrder(root -> left, nodes);`)**: |
| 110 | + - The function first recursively processes the **left subtree**. This ensures that we visit all the nodes in the left subtree first, which is characteristic of in-order traversal. |
| 111 | + |
| 112 | +4. **Storing Node Value (`nodes.push_back(root -> data);`)**: |
| 113 | + - After visiting the left child, the current node's data is added to the `nodes` vector. |
| 114 | + - This will collect the node values in ascending order because in a BST, the left child is always smaller than the parent, and the right child is always larger. |
| 115 | + |
| 116 | +5. **Recursion (`inOrder(root -> right, nodes);`)**: |
| 117 | + - Finally, the function recursively processes the **right subtree** of the current node. |
| 118 | + - The in-order traversal ensures that nodes are processed in the correct order. |
| 119 | + |
| 120 | +**Example Walkthrough:** |
| 121 | +Let’s assume we have the following BST: |
| 122 | + |
| 123 | +``` |
| 124 | + 4 |
| 125 | + / \ |
| 126 | + 2 6 |
| 127 | + / \ / \ |
| 128 | + 1 3 5 7 |
| 129 | +``` |
| 130 | + |
| 131 | +The `inOrder` function would collect the values in the following order: |
| 132 | +1. Start at `4`, go to the left child `2`, go to the left child `1` (add `1` to the vector). |
| 133 | +2. Visit node `2` (add `2` to the vector). |
| 134 | +3. Visit node `3` (add `3` to the vector). |
| 135 | +4. Visit node `4` (add `4` to the vector). |
| 136 | +5. Visit node `5` (add `5` to the vector). |
| 137 | +6. Visit node `6` (add `6` to the vector). |
| 138 | +7. Visit node `7` (add `7` to the vector). |
| 139 | + |
| 140 | +After in-order traversal, the `nodes` vector will contain the sorted values: `[1, 2, 3, 4, 5, 6, 7]`. |
| 141 | + |
| 142 | + |
| 143 | + |
| 144 | +```cpp |
| 145 | + // Step 2: Postorder traversal to replace node values with those from the sorted list |
| 146 | + void inOrderToHeap(Node* root, vector<int> &nodes, int &index){ |
| 147 | + if(root == NULL) return; // Base case: if the node is null, return |
| 148 | + |
| 149 | + // Recurse on the left and right subtrees first (postorder traversal) |
| 150 | + inOrderToHeap(root -> left, nodes, index); |
| 151 | + inOrderToHeap(root -> right, nodes, index); |
| 152 | + |
| 153 | + // Replace the current node's value with the largest remaining value from the sorted list |
| 154 | + root -> data = nodes[index++]; // Assign value from the vector to the node |
| 155 | + } |
| 156 | +``` |
| 157 | + |
| 158 | +#### Explanation: |
| 159 | + |
| 160 | +1. **Function Definition (`inOrderToHeap`)**: |
| 161 | + - The function `inOrderToHeap(Node* root, vector<int> &nodes, int &index)` performs a **postorder traversal** of the binary tree (BST) starting at the root. |
| 162 | + - It takes the current `root` node, the `nodes` vector containing the sorted values, and an `index` reference that helps track which value from the `nodes` vector should be assigned to the current node. |
| 163 | + |
| 164 | +2. **Base Case (`if(root == NULL) return;`)**: |
| 165 | + - If the current node is `NULL`, the function returns because there’s no node to process. |
| 166 | + |
| 167 | +3. **Recursion (`inOrderToHeap(root -> left, nodes, index);`)**: |
| 168 | + - The function first recursively processes the **left subtree** in postorder fashion, ensuring the left children are visited before the parent. |
| 169 | + |
| 170 | +4. **Recursion (`inOrderToHeap(root -> right, nodes, index);`)**: |
| 171 | + - After processing the left subtree, the function processes the **right subtree**, again in postorder fashion. |
| 172 | + |
| 173 | +5. **Assigning Sorted Values (`root -> data = nodes[index++];`)**: |
| 174 | + - After both left and right subtrees have been processed, the function assigns the next value from the `nodes` vector (sorted list) to the current node. |
| 175 | + - The value is assigned from the end of the `nodes` vector (`index++`), which ensures that the largest values are assigned to the root and parent nodes first, preserving the Max Heap property. |
| 176 | + |
| 177 | +**Example Walkthrough:** |
| 178 | +After collecting the sorted values `[1, 2, 3, 4, 5, 6, 7]` in the `nodes` vector, we process the tree in postorder: |
| 179 | +1. We first visit the leftmost child (`1`) and assign the largest value from `nodes` to it. The largest value is `7`, so `1` is replaced with `7`. |
| 180 | +2. Then, we visit node `2`, and the next largest value (`6`) from the `nodes` vector is assigned to it. |
| 181 | +3. This process continues recursively for the entire tree. |
| 182 | + |
| 183 | +After all recursive calls are done, the tree will look like this: |
| 184 | + |
| 185 | +``` |
| 186 | + 7 |
| 187 | + / \ |
| 188 | + 3 6 |
| 189 | + / \ / \ |
| 190 | + 1 2 4 5 |
| 191 | +``` |
| 192 | + |
| 193 | +```cpp |
| 194 | + // Step 3: Main function to convert BST to Max Heap |
| 195 | + void convertToMaxHeapUtil(Node* root) { |
| 196 | + vector<int> nodes; // Create a vector to store the in-order traversal of the BST |
| 197 | + |
| 198 | + // Perform in-order traversal to collect nodes' values |
| 199 | + inOrder(root, nodes); |
| 200 | + |
| 201 | + int index = 0; // Initialize index to 0 (start from the first element in the sorted vector) |
| 202 | + |
| 203 | + // Convert BST to Max Heap using postorder traversal and the sorted node values |
| 204 | + inOrderToHeap(root, nodes, index); |
| 205 | + } |
| 206 | +}; |
| 207 | +``` |
| 208 | + |
| 209 | +#### Explanation: |
| 210 | + |
| 211 | +1. **Function Definition (`convertToMaxHeapUtil`)**: |
| 212 | + - This is the main function that converts the BST to a Max Heap. |
| 213 | + - It first collects the sorted values from the BST using the `inOrder` function and stores them in the `nodes` vector. |
| 214 | + - Then, it uses the `inOrderToHeap` function to assign these values back to the tree nodes in postorder fashion. |
| 215 | + |
| 216 | +2. **In-order Traversal (`inOrder(root, nodes);`)**: |
| 217 | + - It calls the `inOrder` function to collect the sorted values of the BST. |
| 218 | + |
| 219 | +3. **Index Initialization (`int index = 0;`)**: |
| 220 | + - We initialize the `index` to `0` to start assigning values from the smallest to the largest in the `nodes` vector. |
| 221 | + |
| 222 | +4. **Convert to Max Heap (`inOrderToHeap(root, nodes, index);`)**: |
| 223 | + - Finally, the function calls `inOrderToHeap` to convert the BST into a Max Heap by assigning the values from the `nodes` vector to the tree nodes. |
| 224 | + |
| 225 | +### Example Walkthrough |
| 226 | + |
| 227 | +**Input BST:** |
| 228 | +``` |
| 229 | + 4 |
| 230 | + / \ |
| 231 | + 2 6 |
| 232 | + / \ / \ |
| 233 | + 1 3 5 7 |
| 234 | +``` |
| 235 | + |
| 236 | +- **Step 1 (In-order Traversal):** |
| 237 | + The in-order traversal of the tree will give the sorted node values: `[1, 2, 3, 4, 5, 6, 7]`. |
| 238 | + |
| 239 | +- **Step 2 (Postorder Traversal):** |
| 240 | + In postorder traversal, we assign the values from the `nodes` vector to the tree nodes in the following order: |
| 241 | + 1. Start from the leftmost child, assign `7` to `1`. |
| 242 | + 2. Then assign `6` to `2`. |
| 243 | + 3. Continue until the root is assigned `7` and all other nodes get their correct values. |
| 244 | + |
| 245 | +**Output Max Heap:** |
| 246 | +``` |
| 247 | + 7 |
| 248 | + / \ |
| 249 | + 3 6 |
| 250 | + / \ / \ |
| 251 | + 1 2 4 5 |
| 252 | +``` |
| 253 | + |
| 254 | +**Postorder Traversal of Max Heap:** `1 2 3 4 5 6 7`. |
| 255 | + |
| 256 | +### Step 4: Time and Space Complexity |
| 257 | + |
| 258 | +- **Time Complexity**: |
| 259 | + - **In-order traversal (`inOrder`)**: The time complexity of traversing the entire tree is **O(n)**, where `n` is the number of nodes in the tree. |
| 260 | + - **Postorder traversal (`inOrderToHeap`)**: Similarly, replacing the node values using postorder traversal is also **O(n)**. |
| 261 | + - Thus, the overall time complexity is **O(n)**. |
| 262 | + |
| 263 | +- **Space Complexity**: |
| 264 | + - We are using an additional vector (`nodes`) to store the node values. The space complexity for this vector is **O(n)**. |
| 265 | + - The recursion stack used for traversal also takes **O(h)** space, where `h` is the height of the tree. In the worst case (if the tree is skewed), `h` can be `O(n)`, so the total space complexity is **O(n)**. |
| 266 | + |
| 267 | +### Step 5: Additional Recommendations |
| 268 | + |
| 269 | +1. **Edge Cases**: |
| 270 | + - **Empty Tree**: Ensure to handle the case where the root is `NULL`. The code already handles this, but it's worth noting that an empty BST will result in an empty Max Heap. |
| 271 | + - **Single Node Tree**: If the tree has only one node, the tree remains unchanged, but it's important to test this case. |
| 272 | + |
| 273 | +2. **Practice**: |
| 274 | + - Try testing this solution with different tree structures, including balanced trees and skewed trees, to ensure the solution works for all types of input. |
| 275 | + - Understanding tree traversal techniques (in-order, postorder) and how they relate to tree structure manipulation is crucial for solving similar problems in data structures. |
| 276 | + |
| 277 | +3. **Time Complexity Considerations**: |
| 278 | + - The solution is **O(n)** in terms of both time and space, which is optimal for this problem, as every node in the tree needs to be processed at least once. |
| 279 | + |
| 280 | +By understanding these key concepts and applying them, you can effectively approach similar problems involving tree transformations and heap conversions. |
0 commit comments