Perorder to BST
#include <bits/stdc++.h> // Includes common standard libraries (iostream, vector, limits for INT_MIN/MAX)#include "BST.h" // Assumed to contain Node class, levelOrderTraversal
using namespace std; // Use the standard namespace
// Note: The Node class and levelOrderTraversal are assumed to be defined in "BST.h"./*class Node {public: int data; Node* left; Node* right; Node(int data) { // Constructor for Node this->data = data; this->left = NULL; this->right = NULL; }};
void levelOrderTraversal(Node* root) { ... }*/
// Function to construct a BST from its preorder traversal.// 'preorder': The vector containing the preorder traversal sequence.// 'index': A reference to the current position in the 'preorder' vector.// 'min', 'max': The allowed range for the data of the current node being created.// Time Complexity: O(N) where N is number of nodes in preorder.// Space Complexity: O(H) for recursion stack, where H is the height of the constructed BST.Node* createPreorder(vector<int> &preorder, int &index, int min, int max) { // Base Case 1: If all elements from preorder traversal are processed. if(index >= preorder.size()) { return NULL; }
// Get the data for the potential current node. int data = preorder[index];
// Base Case 2: If the current data is outside the allowed range (min, max). // This node does not belong here, it's either for a parent or a different subtree. if(data < min || data > max) { return NULL; }
// Create a new node with the current data. This node is the root of its subtree. Node* temp = new Node(data); index++; // Increment index to move to the next element in preorder for children.
// Recursively build the left child. // For the left child, its maximum value must be the current node's data. // Its minimum value remains the inherited 'min'. temp->left = createPreorder(preorder, index, min, data);
// Recursively build the right child. // For the right child, its minimum value must be the current node's data. // Its maximum value remains the inherited 'max'. temp->right = createPreorder(preorder, index, data, max);
// Return the newly created node (root of this subtree). return temp;}
int main() { Node* root = NULL; // Initialize root of the BST vector<int> preorder; // To store the user-input preorder traversal int index = 0; // Index to track current position in preorder vector
cout << "Enter elements of preorder traversal (-1 to stop) : "; int val; // Read preorder elements until -1 is entered while(cin >> val && val != -1) { preorder.push_back(val); } // Note: The original code had a do-while loop which would push -1 into the vector. // Modified to stop before pushing -1 to keep 'preorder' clean.
// Start building the BST from the preorder traversal. // Initial call uses INT_MIN and INT_MAX as bounds for the very first root. root = createPreorder(preorder, index, INT_MIN, INT_MAX);
cout << endl << "Level Order Traversal of Constructed BST : " << endl; levelOrderTraversal(root); // Print the constructed BST in level order
return 0;}
/*Example Input for preorder traversal:20 10 5 15 13 35 30 42 -1
Expected BST structure (visualize the flow): 20 (root, range -inf to +inf) / \ 10 35 / \ / \ 5 15 30 42 / 13
Level Order Traversal of Constructed BST:20 10 35 5 15 30 42 13
Let's trace:createPreorder(preorder, 0, INT_MIN, INT_MAX) - data = 20. Valid. temp = Node(20). index=1. - temp->left = createPreorder(preorder, 1, INT_MIN, 20) - data = 10. Valid. temp_left = Node(10). index=2. - temp_left->left = createPreorder(preorder, 2, INT_MIN, 10) - data = 5. Valid. temp_left_left = Node(5). index=3. - temp_left_left->left = createPreorder(preorder, 3, INT_MIN, 5) - data = 15. INVALID (15 > 5). Return NULL. - temp_left_left->right = createPreorder(preorder, 3, 5, 10) - data = 15. INVALID (15 > 10). Return NULL. - Return Node(5) - temp_left->right = createPreorder(preorder, 3, 10, 20) - data = 15. Valid. temp_left_right = Node(15). index=4. - temp_left_right->left = createPreorder(preorder, 4, 10, 15) - data = 13. Valid. temp_left_right_left = Node(13). index=5. - temp_left_right_left->left = createPreorder(preorder, 5, 10, 13) - data = 35. INVALID (35 > 13). Return NULL. - temp_left_right_left->right = createPreorder(preorder, 5, 13, 15) - data = 35. INVALID (35 > 15). Return NULL. - Return Node(13) - temp_left_right->right = createPreorder(preorder, 5, 15, 20) - data = 35. INVALID (35 > 20). Return NULL. - Return Node(15) - Return Node(10) - temp->right = createPreorder(preorder, 5, 20, INT_MAX) - data = 35. Valid. temp_right = Node(35). index=6. - temp_right->left = createPreorder(preorder, 6, 20, 35) - data = 30. Valid. temp_right_left = Node(30). index=7. - temp_right_left->left = createPreorder(preorder, 7, 20, 30) - data = 42. INVALID (42 > 30). Return NULL. - temp_right_left->right = createPreorder(preorder, 7, 30, 35) - data = 42. INVALID (42 > 35). Return NULL. - Return Node(30) - temp_right->right = createPreorder(preorder, 7, 35, INT_MAX) - data = 42. Valid. temp_right_right = Node(42). index=8. - temp_right_right->left = createPreorder(preorder, 8, 35, 42) - index = 8. (preorder.size() is 8, so index == preorder.size()). Return NULL. - temp_right_right->right = createPreorder(preorder, 8, 42, INT_MAX) - index = 8. Return NULL. - Return Node(42) - Return Node(35) - Return Node(20)
This trace confirms the logic and builds the correct BST.*/
1. Binary Search Tree (BST) Recap
- A Binary Search Tree (BST) has a strict ordering: for any node, all values in its left subtree are smaller, and all values in its right subtree are larger.
- Preorder Traversal: Visits nodes in the order: Root -> Left Child -> Right Child.
2. Core Idea for Constructing BST from Preorder
- Unlike constructing from In-order + Pre-order/Post-order (which requires both traversals), a BST can be uniquely constructed from just its Preorder traversal. This is because the BST property itself provides implicit information about relative ordering.
- Algorithm Intuition:
- The first element in the preorder sequence is always the root of the current subtree.
- For each subsequent element in the preorder sequence, we determine if it belongs in the left subtree or the right subtree based on its value relative to the current root and the allowed
min
andmax
bounds inherited from its ancestors. - We pass
min
andmax
bounds recursively:- For the left child, the new
max
bound becomes the parent’s value. - For the right child, the new
min
bound becomes the parent’s value.
- For the left child, the new
3. Supporting Components (Briefly)
Node
class: Defines the structure of a BST node (data
,left
,right
).levelOrderTraversal
: Function (assumed inBST.h
) to visualize the constructed BST.INT_MIN
,INT_MAX
: Constants from<limits>
(or implicitly from<bits/stdc++.h>
) used for initial min/max bounds.
4. createPreorder(vector<int> &inorder, int &index, int min, int max)
Function
-
Purpose: Recursively builds the BST from the preorder traversal array.
-
Parameters:
vector<int> &preorder
: The vector containing the preorder traversal sequence. (Note: The parameter name isinorder
in the provided code, but it’s used aspreorder
. I will usepreorder
in comments for clarity).int &index
: A reference to an integer. This is critical. It acts as a global pointer to the current element being processed in thepreorder
array. As we consume elements to build nodes, thisindex
must be updated across all recursive calls.int min
: The minimum permissible value for the node we are currently trying to create. Any value less thanmin
cannot be placed here.int max
: The maximum permissible value for the node we are currently trying to create. Any value greater thanmax
cannot be placed here.
-
Logic Flow:
- Base Case 1: All elements processed:
if(index >= preorder.size())
: If theindex
has gone beyond the last element of thepreorder
array, it means we have no more nodes to form. ReturnNULL
.
- Fetch Candidate Data:
int data = preorder[index];
Get the current element from thepreorder
array. This is a potential node’s value.
- Base Case 2: Value out of bounds:
if(data < min || data > max)
: If the currentdata
is outside the allowedmin
andmax
range for this position in the BST, this node cannot be placed here. It belongs to a different subtree (either an ancestor already processed or a later sibling). ReturnNULL
.
- Create Node:
Node* temp = new Node(data);
If the data is valid for this position, create a newNode
with thisdata
.
- Advance Index:
index++;
Crucially, increment theindex
to move to the next element in thepreorder
sequence. This element will be considered for the left or right child.
- Build Left Subtree:
temp->left = createPreorder(preorder, index, min, data);
Recursively call to build the left child. For the left child, its maximum allowed value is the current node’sdata
. Its minimum allowed value remains the inheritedmin
.
- Build Right Subtree:
temp->right = createPreorder(preorder, index, data, max);
Recursively call to build the right child. For the right child, its minimum allowed value is the current node’sdata
. Its maximum allowed value remains the inheritedmax
.
- Return Node:
return temp;
Return the newly created node as the root of this subtree.
- Base Case 1: All elements processed:
-
Initial Call in
main
:root = createPreorder(preorder, index, INT_MIN, INT_MAX);
- The initial
index
is0
.INT_MIN
andINT_MAX
provide the widest possible range for the very first root node.
5. Complexity Analysis
- Time Complexity:
O(N)
- Each node in the
preorder
array is visited (and potentially created) exactly once. The recursive calls effectively traverse the tree structure.
- Each node in the
- Space Complexity:
O(H)
- Due to the recursion call stack, where
H
is the height of the resulting BST. - Worst Case (Skewed Tree):
H = N
, leading toO(N)
space (e.g., preorder1 2 3 4
). - Best Case (Balanced Tree):
H = log N
, leading toO(log N)
space (e.g., preorder10 5 2 8 15 12 18
).
- Due to the recursion call stack, where