Skip to content

Commit 2cfe89c

Browse files
authored
Create README.md
1 parent a5ee809 commit 2cfe89c

File tree

1 file changed

+356
-0
lines changed

1 file changed

+356
-0
lines changed
Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
<h1 align='center'>Predecessor - And - Successor</h1>
2+
3+
## Problem Statement
4+
5+
**Problem URL :** [Predecessor And Successor](https://www.geeksforgeeks.org/problems/predecessor-and-successor/1)
6+
7+
![image](https://github.com/user-attachments/assets/b0586a77-cf07-4f1a-bacb-0d200665a113)
8+
![image](https://github.com/user-attachments/assets/9067abd4-1b45-4c55-a84a-c6e96d7f6813)
9+
10+
## Problem Explanation
11+
**Problem:**
12+
Given a Binary Search Tree (BST) and a key, find the in-order predecessor and successor of the node containing the given key.
13+
14+
- **Predecessor**: The node with the largest value that is smaller than the key.
15+
- **Successor**: The node with the smallest value that is larger than the key.
16+
17+
If either the predecessor or successor does not exist, return `NULL` for that value.
18+
19+
**Example:**
20+
Consider the following BST:
21+
22+
```
23+
20
24+
/ \
25+
8 22
26+
/ \
27+
4 12
28+
/ \
29+
10 14
30+
```
31+
32+
For `key = 10`:
33+
- **Predecessor** = 8
34+
- **Successor** = 12
35+
36+
**Edge Cases:**
37+
1. Key is the minimum or maximum node in the tree.
38+
2. Key is not found in the BST.
39+
3. The tree has only one node.
40+
41+
---
42+
43+
### Step 2: Approach
44+
45+
**High-Level Overview**:
46+
This approach involves two main steps:
47+
1. **Locate the Node**: Traverse the tree to locate the node with the given key.
48+
2. **Find Predecessor and Successor**:
49+
- For **predecessor**: Find the largest node in the left subtree.
50+
- For **successor**: Find the smallest node in the right subtree.
51+
52+
**Step-by-Step Breakdown**:
53+
1. Traverse the tree from the root.
54+
2. As we traverse, keep track of potential predecessors and successors based on BST properties.
55+
3. Once the key is found, explore its left subtree for the predecessor and right subtree for the successor.
56+
57+
**Pseudocode**:
58+
```plaintext
59+
Initialize `predecessor` and `successor` to NULL.
60+
Set `temp` to the root.
61+
62+
While temp is not NULL:
63+
- If `temp.key` equals the given key, break.
64+
- If `temp.key` is greater than the key:
65+
- Set successor to `temp`.
66+
- Move left.
67+
- Else:
68+
- Set predecessor to `temp`.
69+
- Move right.
70+
71+
If `temp` is NULL, return (predecessor, successor).
72+
73+
In the left subtree of temp:
74+
- Find the rightmost node and set it as predecessor.
75+
76+
In the right subtree of temp:
77+
- Find the leftmost node and set it as successor.
78+
79+
Return (predecessor, successor).
80+
```
81+
82+
## Problem Solution
83+
```cpp
84+
class Solution
85+
{
86+
public:
87+
void findPreSuc(Node* root, Node*& pre, Node*& suc, int key)
88+
{
89+
pre = NULL;
90+
suc = NULL;
91+
92+
// find key
93+
Node* temp = root;
94+
while(temp != NULL){
95+
if(temp -> key == key) break;
96+
97+
if(temp -> key > key){
98+
suc = temp;
99+
temp = temp -> left;
100+
}else{
101+
pre = temp;
102+
temp = temp -> right;
103+
}
104+
}
105+
106+
if(temp == NULL) return;
107+
108+
Node* leftTree = temp -> left;
109+
while(leftTree != NULL){
110+
pre = leftTree;
111+
leftTree = leftTree -> right;
112+
}
113+
114+
Node* rightTree = temp -> right;
115+
while(rightTree != NULL){
116+
suc = rightTree;
117+
rightTree = rightTree -> left;
118+
}
119+
120+
}
121+
};
122+
```
123+
124+
## Problem Solution Explanation
125+
Here’s the given code with a line-by-line breakdown.
126+
127+
Let's break down the provided code for finding the predecessor and successor of a given key in a Binary Search Tree (BST) in a detailed and structured manner.
128+
129+
### Class and Method Declaration
130+
131+
```cpp
132+
class Solution {
133+
public:
134+
```
135+
136+
- **Class Declaration**: We define a class named `Solution`, which encapsulates our method for finding the predecessor and successor.
137+
- **Access Modifier**: `public` means that the following methods can be accessed from outside the class.
138+
139+
### Method Definition
140+
141+
```cpp
142+
void findPreSuc(Node* root, Node*& pre, Node*& suc, int key) {
143+
```
144+
145+
- **Method Signature**: The method `findPreSuc` takes four parameters:
146+
- `Node* root`: A pointer to the root of the BST.
147+
- `Node*& pre`: A reference to a pointer that will store the predecessor node.
148+
- `Node*& suc`: A reference to a pointer that will store the successor node.
149+
- `int key`: The key for which we want to find the predecessor and successor.
150+
151+
### Step 1: Initialize Predecessor and Successor
152+
153+
```cpp
154+
pre = NULL;
155+
suc = NULL;
156+
```
157+
158+
- **Initialization**: Both `pre` and `suc` are initialized to `NULL`, indicating that we have not found any predecessor or successor yet.
159+
160+
### Step 2: Find the Key in the BST
161+
162+
```cpp
163+
Node* temp = root;
164+
while(temp != NULL) {
165+
if(temp->key == key) break;
166+
167+
if(temp->key > key) {
168+
suc = temp;
169+
temp = temp->left;
170+
} else {
171+
pre = temp;
172+
temp = temp->right;
173+
}
174+
}
175+
```
176+
177+
- **Node Traversal**: A temporary pointer `temp` is initialized to `root`, and we enter a loop that continues until `temp` is `NULL`.
178+
- **Key Check**:
179+
- **If `temp->key == key`**: If the current node’s key matches the given key, we break the loop since we found the node.
180+
- **Determine Predecessor and Successor**:
181+
- **If `temp->key > key`**: If the current node's key is greater than the key we are looking for, it could be a potential successor. We set `suc` to `temp` and move left to find a smaller key (which might be closer to the target key).
182+
- **If `temp->key < key`**: If the current node's key is less than the key, it could be a potential predecessor. We set `pre` to `temp` and move right to find a larger key.
183+
184+
**Example**:
185+
Suppose we have a BST like this:
186+
```
187+
20
188+
/ \
189+
10 30
190+
/ \ \
191+
5 15 40
192+
```
193+
- If we are looking for `15`, the traversal goes:
194+
- Start at `20`: `20 > 15`, set `suc` to `20`, go left to `10`.
195+
- At `10`: `10 < 15`, set `pre` to `10`, go right to `15`.
196+
- At `15`: Found the key. Break the loop.
197+
198+
### Step 3: Return if Key Not Found
199+
200+
```cpp
201+
if(temp == NULL) return;
202+
```
203+
204+
- **Check for Existence**: If `temp` is `NULL` after the loop, it means the key does not exist in the BST, so we exit the function.
205+
206+
### Step 4: Find the Predecessor in the Left Subtree
207+
208+
```cpp
209+
Node* leftTree = temp->left;
210+
while(leftTree != NULL) {
211+
pre = leftTree;
212+
leftTree = leftTree->right;
213+
}
214+
```
215+
216+
- **Find Predecessor**: If the key was found, we look for the predecessor:
217+
- We initialize `leftTree` to the left child of `temp`.
218+
- We then find the rightmost node in the left subtree, which is the predecessor.
219+
220+
**Example**: Continuing from the previous example:
221+
- For `temp` being `15`, its left child is `10`. We go to `10` and find its right child (`NULL`), hence `pre` remains `10`.
222+
223+
### Step 5: Find the Successor in the Right Subtree
224+
225+
```cpp
226+
Node* rightTree = temp->right;
227+
while(rightTree != NULL) {
228+
suc = rightTree;
229+
rightTree = rightTree->left;
230+
}
231+
```
232+
233+
- **Find Successor**: Similar to predecessor, but we look for the leftmost node in the right subtree:
234+
- Initialize `rightTree` to the right child of `temp`.
235+
- Find the leftmost node in the right subtree, which will be the successor.
236+
237+
**Example**: Continuing from our previous example:
238+
- For `temp` being `15`, its right child is `NULL`, so `suc` will point to `20`, which was set when we found the key.
239+
Let's go through a few examples of the `findPreSuc` function and explain the expected output in detail. We will consider different scenarios for the predecessor and successor based on the structure of the Binary Search Tree (BST).
240+
241+
### Example 1: Basic Example
242+
243+
**BST Structure:**
244+
```
245+
20
246+
/ \
247+
10 30
248+
/ \ \
249+
5 15 40
250+
```
251+
252+
**Test Case 1: Key = 15**
253+
- **Predecessor**: The largest node in the left subtree of `15` is `10`.
254+
- **Successor**: The smallest node in the right subtree of `15` is `20`.
255+
256+
**Output:**
257+
- `Predecessor = 10`
258+
- `Successor = 20`
259+
260+
**Test Case 2: Key = 30**
261+
- **Predecessor**: The largest node in the left subtree of `30` is `20`.
262+
- **Successor**: There is no right subtree for `30`, so `Successor = NULL`.
263+
264+
**Output:**
265+
- `Predecessor = 20`
266+
- `Successor = NULL`
267+
268+
**Test Case 3: Key = 5**
269+
- **Predecessor**: There is no left subtree for `5`, so `Predecessor = NULL`.
270+
- **Successor**: The smallest node in the right subtree of `5` is `10`.
271+
272+
**Output:**
273+
- `Predecessor = NULL`
274+
- `Successor = 10`
275+
276+
### Example 2: Key Not Present
277+
278+
**BST Structure:**
279+
```
280+
20
281+
/ \
282+
10 30
283+
/ \ \
284+
5 15 40
285+
```
286+
287+
**Test Case 4: Key = 25** (not present in the BST)
288+
- The algorithm would navigate the tree and find that `25` is not present.
289+
- **Predecessor**: The closest smaller key found would be `20` (since `20 < 25`).
290+
- **Successor**: The closest larger key found would be `30` (since `30 > 25`).
291+
292+
**Output:**
293+
- `Predecessor = 20`
294+
- `Successor = 30`
295+
296+
### Example 3: Edge Cases
297+
298+
**BST Structure:**
299+
```
300+
50
301+
/ \
302+
30 70
303+
/ \ \
304+
20 40 80
305+
```
306+
307+
**Test Case 5: Key = 50** (the root itself)
308+
- **Predecessor**: The largest node in the left subtree of `50` is `40`.
309+
- **Successor**: The smallest node in the right subtree of `50` is `70`.
310+
311+
**Output:**
312+
- `Predecessor = 40`
313+
- `Successor = 70`
314+
315+
**Test Case 6: Key = 20** (smallest key)
316+
- **Predecessor**: There is no left subtree for `20`, so `Predecessor = NULL`.
317+
- **Successor**: The smallest node in the right subtree of `20` is `30`.
318+
319+
**Output:**
320+
- `Predecessor = NULL`
321+
- `Successor = 30`
322+
323+
**Test Case 7: Key = 80** (largest key)
324+
- **Predecessor**: The largest node in the left subtree of `80` is `70`.
325+
- **Successor**: There is no right subtree for `80`, so `Successor = NULL`.
326+
327+
**Output:**
328+
- `Predecessor = 70`
329+
- `Successor = NULL`
330+
331+
### Summary of Outputs
332+
333+
Here’s a summary of the outputs for all the test cases:
334+
335+
| **Key** | **Predecessor** | **Successor** |
336+
|---------|------------------|----------------|
337+
| 15 | 10 | 20 |
338+
| 30 | 20 | NULL |
339+
| 5 | NULL | 10 |
340+
| 25 | 20 | 30 |
341+
| 50 | 40 | 70 |
342+
| 20 | NULL | 30 |
343+
| 80 | 70 | NULL |
344+
345+
These outputs illustrate how the `findPreSuc` function identifies the predecessor and successor nodes based on the properties of the BST for various keys, including edge cases and keys that may not be present in the tree.
346+
347+
### Step 5: Time and Space Complexity
348+
349+
- **Time Complexity**: \(O(h)\), where \(h\) is the height of the tree. In a balanced BST, this is \(O(\log n)\), but in the worst case (unbalanced tree), it could be \(O(n)\).
350+
- **Space Complexity**: \(O(1)\), as we are using only a constant amount of extra space (excluding the recursive stack).
351+
352+
353+
**Additional Tips:**
354+
- **Edge Cases**: Consider if the key is not present, or if the key is at the extreme (minimum or maximum).
355+
- **Interactive Examples**: Try running the code on a few examples to see the flow of predecessor and successor updates.
356+

0 commit comments

Comments
 (0)