Trie 是一種 k-ary search tree。它可以儲存大量的字串,並且提供有效率的字串搜尋。
Table of Contents
Trie & TrieNode
Trie 一般會有兩個資料結構,一個是 Trie
,另一個是 TrieNode
。TrieNode
被用來建構整個 tree,而 Trie
只會有一個。TrieNode.terminates
表示從 root 到該 node 的 path 是一個 word。另外,TrieNode.character
不是必要的,因為可以從 parent 的 children 就可以得知該 node 代表的字元。root 不代表任何字元。
public class Trie { private final TrieNode root = new TrieNode(); public Trie(ArrayList<String> list) { for (String word : list) { root.addWord(word); } } public Trie(String[] list) { for (String word : list) { root.addWord(word); } } public boolean contains(String prefix, boolean exact) { TrieNode lastNode = root; for (int i = 0; i < prefix.length(); i++) { lastNode = lastNode.getChild(prefix.charAt(i)); if (lastNode == null) { return false; } } return !exact || lastNode.terminates(); } public boolean contains(String prefix) { return contains(prefix, false); } public void addWord(String word) { root.addWord(word); } }
public class TrieNode { private final HashMap<Character, TrieNode> children = new HashMap<>(); private boolean terminates = false; private char character; public TrieNode() { } public TrieNode(char character) { this.character = character; } public char getChar() { return character; } public void addWord(String word) { if (word == null || word.isEmpty()) { return; } char firstChar = word.charAt(0); TrieNode child = getChild(firstChar); if (child == null) { child = new TrieNode(firstChar); children.put(firstChar, child); } if (word.length() > 1) { child.addWord(word.substring(1)); } else { child.setTerminates(true); } } public TrieNode getChild(char c) { return children.get(c); } public boolean terminates() { return terminates; } public void setTerminates(boolean terminates) { this.terminates = terminates; } }
複雜度
建立字典所需的時間複雜度為 ,其中 為 word[i] 的長度。
搜尋和插入一個 word 所需的時間複雜度為 。
空間複雜度為所有 node 的數量,所以是 。
範例
下面的範例顯示,在插入 word 時,Trie 內部的變化。綠色表示該 node 的 terminates 設為 true。
參考
- Gayle Laakmann McDowell, Cracking the Coding Interview, 6th Edition.
- Trie, Wikipedia.