Skip to content

Commit aca6d01

Browse files
committed
feat: Complete trie implementation and testing
1 parent f5955a5 commit aca6d01

File tree

3 files changed

+213
-1
lines changed

3 files changed

+213
-1
lines changed

src/main/java/dataStructures/trie/Trie.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ public Trie() {
1313
root = new TrieNode();
1414
}
1515

16+
/**
17+
* Inserts a word into the trie.
18+
* @param word
19+
*/
1620
public void insert(String word) {
1721
word = word.toLowerCase(); // ignore case-sensitivity
1822
TrieNode trav = root;
@@ -26,6 +30,11 @@ public void insert(String word) {
2630
trav.isEnd = true; // set word
2731
}
2832

33+
/**
34+
* Searches for a word in the trie.
35+
* @param word
36+
* @return true if the word is found, false otherwise.
37+
*/
2938
public boolean search(String word) {
3039
word = word.toLowerCase();
3140
TrieNode trav = root;
@@ -39,6 +48,10 @@ public boolean search(String word) {
3948
return trav.isEnd;
4049
}
4150

51+
/**
52+
* Deletes a word from the trie.
53+
* @param word
54+
*/
4255
public void delete(String word) {
4356
word = word.toLowerCase();
4457
TrieNode trav = root;
@@ -55,6 +68,10 @@ public void delete(String word) {
5568
// ABOVE ARE STANDARD METHODS OF A TYPICAL TRIE IMPLEMENTATION
5669
// BELOW IMPLEMENTS TWO MORE COMMON / USEFUL METHODS FOR TRIE; IN PARTICULAR, NOTE THE PRUNING METHOD
5770

71+
/**
72+
* Deletes a word from the trie, and also prune redundant nodes. This is useful in keeping the trie compact.
73+
* @param word
74+
*/
5875
public void deleteAndPrune(String word) {
5976
List<TrieNode> trackNodes = new ArrayList<>();
6077
TrieNode trav = root;
@@ -81,6 +98,11 @@ public void deleteAndPrune(String word) {
8198
}
8299
}
83100

101+
/**
102+
* Find all words with the specified prefix.
103+
* @param prefix
104+
* @return a list of words.
105+
*/
84106
public List<String> wordsWithPrefix(String prefix) {
85107
List<String> ret = new ArrayList<>();
86108
TrieNode trav = root;
@@ -98,6 +120,10 @@ public List<String> wordsWithPrefix(String prefix) {
98120
return ret;
99121
}
100122

123+
/**
124+
* Find all words in the trie.
125+
* @return a list of words.
126+
*/
101127
public List<String> getAllWords() {
102128
List<StringBuilder> allWords = getAllSuffixFromNode(root);
103129
List<String> ret = new ArrayList<>();
@@ -107,6 +133,11 @@ public List<String> getAllWords() {
107133
return ret;
108134
}
109135

136+
/**
137+
* Helper method to get suffix from the node.
138+
* @param node
139+
* @return
140+
*/
110141
private List<StringBuilder> getAllSuffixFromNode(TrieNode node) {
111142
List<StringBuilder> ret = new ArrayList<>();
112143
if (node.isEnd) {
@@ -122,4 +153,25 @@ private List<StringBuilder> getAllSuffixFromNode(TrieNode node) {
122153
}
123154
return ret;
124155
}
156+
157+
// BELOW IS A METHOD THAT IS USED FOR TESTING PURPOSES ONLY
158+
159+
/**
160+
* Helper method for testing purposes.
161+
* @param str
162+
* @param pos
163+
* @return
164+
*/
165+
public Boolean checkNodeExistsAtPosition(String str, Integer pos) {
166+
TrieNode trav = root;
167+
for (int i = 0; i < pos; i++) {
168+
char c = str.charAt(i);
169+
if (trav.children.containsKey(c)) {
170+
trav = trav.children.get(c);
171+
} else {
172+
return false;
173+
}
174+
}
175+
return true;
176+
}
125177
}
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
package dataStructures.trie;
22

3+
import java.util.HashMap;
34
import java.util.Map;
45

56
/**
67
* Implementation of a TrieNode.
78
*/
89
public class TrieNode {
10+
// CHECKSTYLE:OFF: VisibilityModifier
911
public Map<Character, TrieNode> children; // or an array of size 26 (assume not case-sensitive) to denote each char
10-
public boolean isEnd; // the marker to indicate whether the path from the root to this node forms a known word
12+
// CHECKSTYLE:OFF: VisibilityModifier
13+
public boolean isEnd; // a marker to indicate whether the path from the root to this node forms a known word
14+
15+
/**
16+
* Basic constructor.
17+
*/
18+
public TrieNode() {
19+
children = new HashMap<Character, TrieNode>();
20+
isEnd = false;
21+
}
1122
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package dataStructures.trie;
2+
3+
import java.util.Arrays;
4+
import java.util.Collections;
5+
import java.util.List;
6+
7+
import org.junit.Assert;
8+
import org.junit.Test;
9+
10+
/**
11+
* insert
12+
* search
13+
* delete
14+
* deleteAndPrune
15+
* wordsWithPrefix
16+
* getAllWords
17+
*/
18+
public class TrieTest {
19+
@Test
20+
public void search_shouldFindWordIfExists() {
21+
Trie trie = new Trie();
22+
trie.insert("cs2040s");
23+
trie.insert("cs3230");
24+
trie.insert("cs4231");
25+
trie.insert("cs4234");
26+
27+
Assert.assertTrue(trie.search("cs2040s"));
28+
Assert.assertTrue(trie.search("cs4231"));
29+
Assert.assertFalse(trie.search("cs2040"));
30+
}
31+
32+
@Test
33+
public void delete_shouldNotFindDeletedWord() {
34+
Trie trie = new Trie();
35+
trie.insert("cs2040s");
36+
trie.insert("cs3230");
37+
trie.insert("cs4231");
38+
trie.insert("cs4234");
39+
40+
Assert.assertTrue(trie.search("cs4231"));
41+
trie.delete("cs4231");
42+
Assert.assertFalse(trie.search("cs4231"));
43+
}
44+
45+
@Test
46+
public void deleteAndPrune_shouldNotFindDeletedWord() {
47+
Trie trie = new Trie();
48+
trie.insert("cs2040s");
49+
trie.insert("cs3230");
50+
trie.insert("cs4231");
51+
trie.insert("cs4234");
52+
53+
Assert.assertTrue(trie.search("cs4231"));
54+
trie.deleteAndPrune("cs4231");
55+
Assert.assertFalse(trie.search("cs4231"));
56+
}
57+
58+
@Test
59+
public void deleteAndPrune_shouldPrune() {
60+
Trie trie = new Trie();
61+
trie.insert("cs2040s");
62+
trie.insert("cs3230");
63+
trie.insert("cs4231");
64+
trie.insert("cs4234");
65+
trie.insert("cs4261");
66+
67+
trie.deleteAndPrune("cs4261");
68+
Assert.assertFalse(trie.checkNodeExistsAtPosition("cs4261", 5));
69+
Assert.assertTrue(trie.checkNodeExistsAtPosition("cs4261", 4)); // because of presence of other "cs42"s
70+
trie.deleteAndPrune("cs3230");
71+
Assert.assertFalse(trie.checkNodeExistsAtPosition("cs3230", 3));
72+
Assert.assertTrue(trie.checkNodeExistsAtPosition("cs3230", 2));
73+
}
74+
75+
@Test
76+
public void wordsWithPrefix_shouldDisplayCurrentWordsThatMatches() {
77+
Trie trie = new Trie();
78+
trie.insert("biology");
79+
trie.insert("biodiversity");
80+
trie.insert("bioinformatics");
81+
trie.insert("biotechnology");
82+
trie.insert("biotic");
83+
trie.insert("bicycle");
84+
trie.insert("bijection");
85+
trie.insert("symbiotic");
86+
trie.insert("submarine");
87+
trie.insert("submerged");
88+
89+
List<String> resultA = trie.wordsWithPrefix("bio");
90+
Collections.sort(resultA);
91+
List<String> expectedA = Arrays.asList("biology", "biodiversity", "bioinformatics", "biotechnology", "biotic");
92+
Collections.sort(expectedA);
93+
Assert.assertEquals(expectedA, resultA);
94+
95+
List<String> resultB = trie.wordsWithPrefix("sub");
96+
Collections.sort(resultB);
97+
List<String> expectedB = Arrays.asList("submarine", "submerged");
98+
Collections.sort(expectedB);
99+
Assert.assertEquals(expectedB, resultB);
100+
101+
trie.delete("biodiversity");
102+
trie.delete("biotic");
103+
104+
List<String> resultC = trie.wordsWithPrefix("bio");
105+
Collections.sort(resultC);
106+
List<String> expectedC = Arrays.asList("biology", "bioinformatics", "biotechnology");
107+
Collections.sort(expectedC);
108+
Assert.assertEquals(expectedC, resultC);
109+
110+
List<String> resultD = trie.wordsWithPrefix("sy");
111+
Collections.sort(resultD);
112+
List<String> expectedD = Arrays.asList("symbiotic");
113+
Collections.sort(expectedD);
114+
Assert.assertEquals(expectedD, resultD);
115+
116+
trie.delete("symbiotic");
117+
118+
List<String> resultE = trie.wordsWithPrefix("sy");
119+
Collections.sort(resultE);
120+
List<String> expectedE = Arrays.asList();
121+
Collections.sort(expectedE);
122+
Assert.assertEquals(expectedE, resultE);
123+
}
124+
125+
@Test
126+
public void getAllWords_shouldDisplayCurrentWords() {
127+
Trie trie = new Trie();
128+
trie.insert("eldric");
129+
trie.insert("seth");
130+
trie.insert("gilbert");
131+
trie.insert("KAI TING"); // converted to lower-case
132+
trie.insert("daniel");
133+
trie.insert("andre");
134+
135+
List<String> resultA = trie.getAllWords();
136+
Collections.sort(resultA);
137+
List<String> expectedA = Arrays.asList("eldric", "seth", "gilbert", "kai ting", "andre", "daniel");
138+
Collections.sort(expectedA);
139+
Assert.assertEquals(expectedA, resultA);
140+
141+
trie.delete("daniel");
142+
trie.delete("eldric");
143+
List<String> resultB = trie.getAllWords();
144+
Collections.sort(resultB);
145+
List<String> expectedB = Arrays.asList("seth", "gilbert", "kai ting", "andre");
146+
Collections.sort(expectedB);
147+
Assert.assertEquals(expectedB, resultB);
148+
}
149+
}

0 commit comments

Comments
 (0)