1+ """
2+ Implementation of Trie (Prefix Tree) data structure.
3+ """
4+
5+ __all__ = [
6+ 'Trie'
7+ ]
8+
9+ class TrieNode :
10+ """
11+ Represents a node in the Trie.
12+ """
13+ __slots__ = ['children' , 'is_end_of_word' ]
14+
15+ def __init__ (self ):
16+ """
17+ Initializes a TrieNode.
18+ """
19+ self .children = {}
20+ self .is_end_of_word = False
21+
22+ class Trie :
23+ """
24+ Represents a Trie (Prefix Tree) data structure.
25+
26+ Examples
27+ ========
28+
29+ >>> from pydatastructs.trees.trie import Trie
30+ >>> trie = Trie()
31+ >>> trie.insert("apple")
32+ >>> trie.search("apple")
33+ True
34+ >>> trie.search("app")
35+ False
36+ >>> trie.starts_with("app")
37+ True
38+ >>> trie.insert("app")
39+ >>> trie.search("app")
40+ True
41+ >>> trie.delete("apple")
42+ True
43+ >>> trie.search("apple")
44+ False
45+ >>> trie.search("app")
46+ True
47+ """
48+ __slots__ = ['root' ]
49+
50+ def __init__ (self ):
51+ """
52+ Initializes an empty Trie.
53+ """
54+ self .root = TrieNode ()
55+
56+ def insert (self , word ):
57+ """
58+ Inserts a word into the trie.
59+
60+ Parameters
61+ ==========
62+
63+ word: str
64+ The word to insert
65+
66+ Returns
67+ =======
68+
69+ None
70+ """
71+ node = self .root
72+ for char in word :
73+ if char not in node .children :
74+ node .children [char ] = TrieNode ()
75+ node = node .children [char ]
76+ node .is_end_of_word = True
77+
78+ def search (self , word ):
79+ """
80+ Returns True if the word is in the trie.
81+
82+ Parameters
83+ ==========
84+
85+ word: str
86+ The word to search for
87+
88+ Returns
89+ =======
90+
91+ bool
92+ True if the word is in the trie, False otherwise
93+ """
94+ node = self ._get_node (word )
95+ return node is not None and node .is_end_of_word
96+
97+ def starts_with (self , prefix ):
98+ """
99+ Returns True if there is any word in the trie
100+ that starts with the given prefix.
101+
102+ Parameters
103+ ==========
104+
105+ prefix: str
106+ The prefix to check
107+
108+ Returns
109+ =======
110+
111+ bool
112+ True if there is any word with the given prefix,
113+ False otherwise
114+ """
115+ return self ._get_node (prefix ) is not None
116+
117+ def delete (self , word ):
118+ """
119+ Deletes a word from the trie if it exists.
120+
121+ Parameters
122+ ==========
123+
124+ word: str
125+ The word to delete
126+
127+ Returns
128+ =======
129+
130+ bool
131+ True if the word was deleted, False if it wasn't in the trie
132+ """
133+ def _delete_helper (node , word , depth = 0 ):
134+ # If we've reached the end of the word
135+ if depth == len (word ):
136+ # If the word exists in the trie
137+ if node .is_end_of_word :
138+ node .is_end_of_word = False
139+ # Return True if this node can be deleted
140+ # (has no children and is not end of another word)
141+ return len (node .children ) == 0
142+ return False
143+
144+ char = word [depth ]
145+ if char not in node .children :
146+ return False
147+
148+ should_delete_child = _delete_helper (node .children [char ], word , depth + 1 )
149+
150+ # If we should delete the child
151+ if should_delete_child :
152+ del node .children [char ]
153+ # Return True if this node can be deleted
154+ # (has no children and is not end of another word)
155+ return len (node .children ) == 0 and not node .is_end_of_word
156+
157+ return False
158+
159+ if not word :
160+ return False
161+
162+ return True if _delete_helper (self .root , word ) else self .search (word )
163+
164+ def _get_node (self , prefix ):
165+ """
166+ Returns the node at the end of the prefix, or None if not found.
167+
168+ Parameters
169+ ==========
170+
171+ prefix: str
172+ The prefix to find
173+
174+ Returns
175+ =======
176+
177+ TrieNode or None
178+ The node at the end of the prefix, or None if the prefix doesn't exist
179+ """
180+ node = self .root
181+ for char in prefix :
182+ if char not in node .children :
183+ return None
184+ node = node .children [char ]
185+ return node
0 commit comments