Skip to content

Commit 94a56b1

Browse files
authored
Update README.md
1 parent 70cc029 commit 94a56b1

File tree

1 file changed

+120
-5
lines changed
  • 21 - Trie Data Structure Problems/01 - Example

1 file changed

+120
-5
lines changed

21 - Trie Data Structure Problems/01 - Example/README.md

Lines changed: 120 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,12 +304,127 @@ void removeWord(string word) {
304304
}
305305
```
306306

307-
#### **Example Flow**
308-
Delete `"cat"`:
309-
1. Unmark `isTerminal` at `'t'`.
310-
2. Delete `'t'` if it has no children.
311-
3. Repeat for `'a'` and `'c'`.
307+
The `removeUtil` function is a recursive helper function used to delete a word from a **Trie**. It traverses the Trie from the root to the end of the word, removes the word's presence, and handles cleaning up unused nodes if necessary. Here's a detailed breakdown of the code:
308+
309+
310+
### **Function Prototype**
311+
```cpp
312+
bool removeUtil(TrieNode* root, string& word, int index)
313+
```
314+
- **Parameters**:
315+
1. `TrieNode* root`: The current node being processed.
316+
2. `string& word`: The word we want to remove.
317+
3. `int index`: The current index of the word's character being processed.
318+
- **Returns**:
319+
- `true`: If the child node can be deleted because it is no longer needed.
320+
- `false`: If the child node or any part of the Trie should not be deleted.
321+
322+
323+
### **Detailed Explanation**
324+
#### **Base Case (Line 2-10)**: End of the word
325+
```cpp
326+
if (index == word.size()) {
327+
if (!root->isTerminal)
328+
return false; // Word doesn't exist in the Trie.
329+
root->isTerminal = false; // Mark the node as non-terminal (not the end of any word).
330+
331+
for (int i = 0; i < 26; i++)
332+
if (root->children[i] != NULL)
333+
return false; // Node has children, cannot delete this node.
334+
return true; // Node has no children, safe to delete this node.
335+
}
336+
```
337+
- **Explanation**:
338+
- If the end of the word (`index == word.size()`) is reached:
339+
- Check if `root->isTerminal` is `true`:
340+
- If `false`: The word does not exist, so return `false`.
341+
- If `true`: Mark `isTerminal` as `false` because the word is no longer in the Trie.
342+
- Check if the current node has any children using the `for` loop:
343+
- If children exist, return `false` (indicating the node cannot be deleted because it is part of another word).
344+
- If no children, return `true` (indicating the node is safe to delete).
345+
346+
347+
#### **Recursive Case (Line 12-28)**: Traversing the Trie
348+
```cpp
349+
int charIndex = word[index] - 'a'; // Compute the index of the current character.
350+
TrieNode* child = root->children[charIndex]; // Get the corresponding child node.
351+
352+
if (child == NULL)
353+
return false; // Word doesn't exist in the Trie.
354+
```
355+
- **Explanation**:
356+
- Calculate the `charIndex` for the current character.
357+
- Check if the corresponding child node exists:
358+
- If `NULL`: The word does not exist, so return `false`.
359+
360+
361+
#### **Recursive Call and Cleanup**
362+
```cpp
363+
bool shouldDeleteChild = removeUtil(child, word, index + 1); // Recurse for the next character.
364+
365+
if (shouldDeleteChild) {
366+
delete child; // Free memory for the unused child node.
367+
root->children[charIndex] = NULL; // Remove the pointer to the deleted child.
368+
369+
for (int i = 0; i < 26; i++)
370+
if (root->children[i] != NULL)
371+
return false; // Current node cannot be deleted because it has other children.
372+
return true; // Current node is safe to delete.
373+
}
374+
```
375+
- **Explanation**:
376+
- Recursively call `removeUtil` for the child node and the next character (`index + 1`).
377+
- If the child node is safe to delete (`shouldDeleteChild == true`):
378+
- Delete the child node (`delete child`).
379+
- Set `root->children[charIndex]` to `NULL`.
380+
- Check if the current node still has any children:
381+
- If children exist, return `false` (node cannot be deleted because it's still part of another word).
382+
- If no children, return `true` (node is safe to delete).
383+
384+
385+
#### **Final Case**
386+
```cpp
387+
return false; // Default case: Do not delete this node.
388+
```
389+
- **Explanation**:
390+
- If none of the above conditions are met, return `false`, indicating the current node cannot be deleted.
391+
392+
393+
### **Wrapper Function**
394+
```cpp
395+
void removeWord(string word) {
396+
removeUtil(root, word, 0);
397+
}
398+
```
399+
- **Purpose**:
400+
- The `removeWord` function provides a user-friendly interface to remove a word from the Trie.
401+
- It simply calls the helper function `removeUtil` with the root node, the word, and an initial index of `0`.
402+
403+
404+
### **Example Walkthrough**
405+
#### Trie Structure Before Removal:
406+
Suppose the Trie contains the words: `"cat"`, `"can"`, and `"car"`. Now we remove `"can"`.
407+
408+
1. **Recursive Traversal:**
409+
- Traverse the Trie for `'c'` → `'a'` → `'n'`.
410+
- Mark `'n'` as non-terminal and check if it has children.
411+
- `'n'` has no children, so delete it.
412+
413+
2. **Backtrack to `'a'`:**
414+
- After deleting `'n'`, check `'a'` for other children.
415+
- `'a'` still has children (`'t'` and `'r'`), so it cannot be deleted.
416+
417+
3. **Final Trie Structure:**
418+
- `"cat"` and `"car"` remain intact.
419+
- `"can"` is removed.
420+
421+
### **Key Features**
422+
1. **Handles Partial Overlaps:**
423+
- Ensures nodes used by multiple words are not deleted prematurely.
424+
2. **Memory Efficiency:**
425+
- Frees unused nodes to optimize space.
312426
427+
This function is essential for maintaining the integrity of the Trie while efficiently removing words.
313428
314429
---
315430
### **Complexity Analysis**

0 commit comments

Comments
 (0)