A Trie (also known as a Prefix Tree) is a tree-based data structure that is used to store a dynamic set of strings, where the keys are usually strings. It is particularly useful for tasks such as:
A Trie typically has the following components:
class TrieNode {
// HashMap to store children nodes
Map<Character, TrieNode> children;
boolean isEndOfWord;
public TrieNode() {
children = new HashMap<>();
isEndOfWord = false;
}
}Inserting a word into the Trie involves adding characters one by one. If the character already exists as a child node, move to that node; otherwise, create a new node for that character.
class Trie {
private TrieNode root;
public Trie() {
root = new TrieNode();
}
// Insert a word into the trie
public void insert(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
node = node.children.computeIfAbsent(c, k -> new TrieNode());
}
node.isEndOfWord = true;
}
}Searching for a word in the Trie involves traversing the Trie node-by-node following the word's characters. If the traversal reaches the end of the word and the node is marked as isEndOfWord = true, then the word exists in the Trie.
// Search if the word exists in the trie
public boolean search(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
node = node.children.get(c);
if (node == null) return false;
}
return node.isEndOfWord;
}This operation checks whether any word in the Trie starts with a given prefix. It only needs to traverse the characters of the prefix, not the whole word.
// Check if there's any word in the trie that starts with the given prefix
public boolean startsWith(String prefix) {
TrieNode node = root;
for (char c : prefix.toCharArray()) {
node = node.children.get(c);
if (node == null) return false;
}
return true;
}To delete a word, you need to remove nodes that are part of the word and ensure that the nodes are removed only if they are not part of any other word. This is a bit tricky and requires backtracking.
Let’s put everything together into a full example.
import java.util.HashMap;
import java.util.Map;
class TrieNode {
Map<Character, TrieNode> children;
boolean isEndOfWord;
public TrieNode() {
children = new HashMap<>();
isEndOfWord = false;
}
}
class Trie {
private TrieNode root;
public Trie() {
root = new TrieNode();
}
// Insert a word into the trie
public void insert(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
node = node.children.computeIfAbsent(c, k -> new TrieNode());
}
node.isEndOfWord = true;
}
// Search if the word exists in the trie
public boolean search(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
node = node.children.get(c);
if (node == null) return false;
}
return node.isEndOfWord;
}
// Check if there's any word in the trie that starts with the given prefix
public boolean startsWith(String prefix) {
TrieNode node = root;
for (char c : prefix.toCharArray()) {
node = node.children.get(c);
if (node == null) return false;
}
return true;
}
// Delete a word from the trie
public boolean delete(String word) {
return deleteHelper(root, word, 0);
}
private boolean deleteHelper(TrieNode node, String word, int index) {
if (index == word.length()) {
if (!node.isEndOfWord) return false; // Word not found
node.isEndOfWord = false;
return node.children.isEmpty(); // If no children, it can be deleted
}
char ch = word.charAt(index);
TrieNode childNode = node.children.get(ch);
if (childNode == null) return false; // Word not found
boolean shouldDeleteChild = deleteHelper(childNode, word, index + 1);
if (shouldDeleteChild) {
node.children.remove(ch);
return node.children.isEmpty() && !node.isEndOfWord; // If the node can be deleted
}
return false;
}
}
public class Main {
public static void main(String[] args) {
Trie trie = new Trie();
// Insert words
trie.insert("apple");
trie.insert("app");
trie.insert("bat");
trie.insert("batman");
// Search words
System.out.println(trie.search("apple")); // true
System.out.println(trie.search("app")); // true
System.out.println(trie.search("bat")); // true
System.out.println(trie.search("bats")); // false
// Prefix search
System.out.println(trie.startsWith("ba")); // true
System.out.println(trie.startsWith("cat")); // false
// Delete words
trie.delete("batman");
System.out.println(trie.search("batman")); // false
System.out.println(trie.search("bat")); // true
}
}| Operation | Time Complexity | Space Complexity |
|---|---|---|
insert(word) | O(L) | O(L) |
search(word) | O(L) | O(L) |
startsWith(prefix) | O(L) | O(L) |
delete(word) | O(L) | O(L) |
Where:
L is the length of the word.This cheat sheet provides the basic structure, operations, and a full example to help you get started with implementing Tries in Java!