Definition and Algorithms of Trie
Trie Algorithm
Definition of Trie
- Prefix Tree, also called Dictionary Tree or Key Tree, is a tree-based data structure, a variant of the hash tree.
- Usage: Efficiently store and sort a large number of strings, often used in search engines for word frequency counting.
- Advantages: Reduces unnecessary string comparisons by leveraging common prefixes.
- Core Idea: Trade space for time, using shared prefixes to speed up lookups.
Three Basic Properties of a Trie
- The root node contains no character; each other node contains exactly one character.
- The path from the root to a node forms the string represented by that node.
- All child nodes of a node have distinct characters.
Comparison with Hash Lookup
- Hash tree explanation: Merkle tree
- Trie complexity: , where is the string length.
- Hash lookup complexity:
- Hash tables do not support dynamic queries (queries can only be made after full input is provided).
- Trie supports dynamic queries, but may consume more memory.
Trie Data Structure
Java Implementation
- Trie Node Initialization
public class TrieNode {
int count;
int prefix;
TrieNode[] nextNode = new TrieNode[26];
public TrieNode() {
count = 0;
prefix = 0;
}
}
- Insert a Word
public static void insert(TrieNode root, String str) {
if (root == null || str.length() == 0) return;
char[] c = str.toCharArray();
for (int i = 0; i < str.length(); i++) {
if (root.nextNode[c[i] - 'a'] == null) {
root.nextNode[c[i] - 'a'] = new TrieNode();
}
root = root.nextNode[c[i] - 'a'];
root.prefix++;
}
root.count++;
}
- Search Word Count / Prefix Count
public static int search(TrieNode root, String str) {
if (root == null || str.length() == 0) return -1;
char[] c = str.toCharArray();
for (int i = 0; i < str.length(); i++) {
if (root.nextNode[c[i] - 'a'] == null) return -1;
root = root.nextNode[c[i] - 'a'];
}
return root.count == 0 ? -1 : root.count;
}
public static int searchPrefix(TrieNode root, String str) {
if (root == null || str.length() == 0) return -1;
char[] c = str.toCharArray();
for (int i = 0; i < str.length(); i++) {
if (root.nextNode[c[i] - 'a'] == null) return -1;
root = root.nextNode[c[i] - 'a'];
}
return root.prefix;
}
C++ Implementation
class Trie {
public:
int count; // Number of words ending at this node
int prefix; // Number of words with this prefix
Trie* nextNode[26];
Trie() {
count = 0;
prefix = 0;
for(int i = 0; i < 26; i++) nextNode[i] = nullptr;
}
void insert(string word) {
if(word.empty()) return;
Trie* p = this;
for(char c : word) {
if(p->nextNode[c - 'a'] == nullptr)
p->nextNode[c - 'a'] = new Trie();
p = p->nextNode[c - 'a'];
p->prefix++;
}
p->count++;
}
bool search(string word) {
if(word.empty()) return false;
Trie* p = this;
for(char c : word) {
if(p->nextNode[c - 'a'] == nullptr) return false;
p = p->nextNode[c - 'a'];
}
return p->count != 0;
}
bool startsWith(string prefix) {
if(prefix.empty()) return false;
Trie* p = this;
for(char c : prefix) {
if(p->nextNode[c - 'a'] == nullptr) return false;
p = p->nextNode[c - 'a'];
}
return p->prefix != 0;
}
};
/**
* Usage:
* Trie* obj = new Trie();
* obj->insert(word);
* bool exists = obj->search(word);
* bool hasPrefix = obj->startsWith(prefix);
*/
Reference: Trie Tree