Skip to content

Commit

Permalink
Implement trie algorithm with insert, search, starts_with, and delete…
Browse files Browse the repository at this point in the history
… methods; add comprehensive test suite
  • Loading branch information
staging-devin-ai-integration[bot] committed Aug 23, 2024
1 parent 1ee7c81 commit fbd1ea0
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 0 deletions.
59 changes: 59 additions & 0 deletions test_trie.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import unittest
from trie import Trie

class TestTrie(unittest.TestCase):
def setUp(self):
self.trie = Trie()

def test_insert_and_search(self):
self.trie.insert("apple")
self.assertTrue(self.trie.search("apple"))
self.assertFalse(self.trie.search("app"))
self.assertFalse(self.trie.search("apples"))

def test_starts_with(self):
self.trie.insert("apple")
self.assertTrue(self.trie.starts_with("app"))
self.assertTrue(self.trie.starts_with("apple"))
self.assertFalse(self.trie.starts_with("apq"))

def test_delete(self):
self.trie.insert("apple")
self.trie.insert("app")
self.assertTrue(self.trie.delete("apple"))
self.assertFalse(self.trie.search("apple"))
self.assertTrue(self.trie.search("app"))
self.assertFalse(self.trie.delete("apple"))

def test_empty_string(self):
self.trie.insert("")
self.assertTrue(self.trie.search(""))
self.assertTrue(self.trie.starts_with(""))
self.assertTrue(self.trie.delete(""))

def test_case_sensitivity(self):
self.trie.insert("Apple")
self.assertTrue(self.trie.search("Apple"))
self.assertFalse(self.trie.search("apple"))

def test_non_alphabetic_characters(self):
self.trie.insert("hello123")
self.assertTrue(self.trie.search("hello123"))
self.assertFalse(self.trie.search("hello"))

def test_overlapping_prefixes(self):
self.trie.insert("car")
self.trie.insert("carpet")
self.assertTrue(self.trie.search("car"))
self.assertTrue(self.trie.search("carpet"))
self.assertTrue(self.trie.starts_with("car"))

def test_delete_prefix(self):
self.trie.insert("car")
self.trie.insert("carpet")
self.assertTrue(self.trie.delete("car"))
self.assertFalse(self.trie.search("car"))
self.assertTrue(self.trie.search("carpet"))

if __name__ == '__main__':
unittest.main()
60 changes: 60 additions & 0 deletions trie.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from typing import Union

class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False

class Trie:
def __init__(self):
self.root = TrieNode()

def insert(self, word: str) -> None:
node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end_of_word = True

def search(self, word: str) -> bool:
node = self._traverse(word)
return node is not None and node.is_end_of_word

def starts_with(self, prefix: str) -> bool:
return self._traverse(prefix) is not None

def delete(self, word: str) -> bool:
def _delete_helper(node, word, index):
if index == len(word):
if not node.is_end_of_word:
return False
node.is_end_of_word = False
return len(node.children) == 0

char = word[index]
if char not in node.children:
return False

should_delete_child = _delete_helper(node.children[char], word, index + 1)

if should_delete_child:
del node.children[char]
return len(node.children) == 0 and not node.is_end_of_word
return False

if not word:
if self.root.is_end_of_word:
self.root.is_end_of_word = False
return True
return False

return _delete_helper(self.root, word, 0)

def _traverse(self, word: str) -> Union[TrieNode, None]:
node = self.root
for char in word:
if char not in node.children:
return None
node = node.children[char]
return node
68 changes: 68 additions & 0 deletions trie_plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Trie Algorithm Implementation Plan

## 1. Structure
- Create a `TrieNode` class:
- `children`: A dictionary to store child nodes (key: character, value: TrieNode)
- `is_end_of_word`: A boolean to mark the end of a word

- Create a `Trie` class:
- `root`: A TrieNode instance to serve as the root of the trie

## 2. Methods
### Trie class methods:
a. `insert(word: str) -> None`:
- Insert a word into the trie
- Time complexity: O(m), where m is the length of the word

b. `search(word: str) -> bool`:
- Search for a word in the trie
- Return True if the word exists, False otherwise
- Time complexity: O(m), where m is the length of the word

c. `starts_with(prefix: str) -> bool`:
- Check if there is any word in the trie that starts with the given prefix
- Return True if such a word exists, False otherwise
- Time complexity: O(m), where m is the length of the prefix

d. `delete(word: str) -> bool`:
- Remove a word from the trie if it exists
- Return True if the word was deleted, False if it wasn't found
- Time complexity: O(m), where m is the length of the word

## 3. Edge Cases to Consider
- Empty string input
- Case sensitivity (decide whether to handle case-insensitive operations)
- Non-alphabetic characters
- Overlapping prefixes
- Deleting a word that is a prefix of another word

## 4. Testing
- Create a separate test file to verify the functionality of the Trie class
- Test cases should include:
- Inserting and searching for words
- Searching for non-existent words
- Checking prefixes
- Deleting words (including words that are prefixes of other words)
- Edge cases mentioned above

## 5. Implementation Steps
1. Create the `TrieNode` class
2. Implement the `Trie` class with its constructor
3. Implement the `insert` method
4. Implement the `search` method
5. Implement the `starts_with` method
6. Implement the `delete` method
7. Create a test file and write comprehensive tests
8. Run tests and debug if necessary

## 6. Time and Space Complexity Analysis
- Time Complexity:
- Insertion: O(m) where m is the length of the word
- Search: O(m) where m is the length of the word
- Prefix search: O(m) where m is the length of the prefix
- Deletion: O(m) where m is the length of the word

- Space Complexity:
- O(n * m) where n is the number of words and m is the average length of the words

This implementation will provide an efficient solution for prefix-based word storage and retrieval, which is the primary use case for a trie data structure.

0 comments on commit fbd1ea0

Please sign in to comment.