1.本文原文來自於leetcode上的算法題Implement Trie的解決方案.
2.原文地址
3.新手獻醜了,但願你們輕拍~(微笑)java
算法題:
經過編寫插入、查詢、判斷開頭等方法完成一個trie樹。node
例子:算法
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // returns true
trie.search("app"); // returns false
trie.startsWith("app"); // returns true
trie.insert("app");
複製代碼
提示:數組
總結:
這篇文章是寫給中等水平的讀者的,將會介紹數據結構trie(前綴樹)和其中的常見操做。數據結構
2.1應用:
trie(前綴樹)是一種樹形數據結構,經常用來在字符串的數據集中檢索一個關鍵詞。目前,trie數據結構已經被高效地應用在了不少領域:
(1)自動填充
app
trie優於hash表的另一個緣由是,但hash表的數據規模擴大後,將會出現不少的hash碰撞,所以查詢時間複雜度將會提升到O (n),n 是插入的關鍵詞的個數。而相比於hash表,trie在存儲不少具備共同前綴的關鍵詞時須要的空間更少。在這個例子裏trie只須要O (m)的時間複雜度(m 是關鍵詞的長度)。而在平衡樹裏查詢一個關鍵詞,則須要花費O (m logn)
2.2 trie節點結構
trie是一個有根樹,它的節點有如下幾個字段:spa
class TrieNode {
// R links to node children
private TrieNode[] links;
private final int R = 26;
private boolean isEnd;
public TrieNode() {
links = new TrieNode[R];
}
public boolean containsKey(char ch) {
return links[ch -'a'] != null;
}
public TrieNode get(char ch) {
return links[ch -'a'];
}
public void put(char ch, TrieNode node) {
links[ch -'a'] = node;
}
public void setEnd() {
isEnd = true;
}
public boolean isEnd() {
return isEnd;
}
}
複製代碼
2.3 trie中最多見的操做——添加和查詢關鍵詞
(1)添加關鍵詞到trie中
咱們經過遍歷trie來插入關鍵詞。咱們從根節點開始,搜尋和關鍵詞第一個字母對應的鏈接,這裏通常有兩種狀況:設計
咱們重複這個步驟,直處處理完關鍵詞的最後一個字母,而後標記最後的節點爲結束節點。算法結束。 code
class Trie {
private TrieNode root;
public Trie() {
root = new TrieNode();
}
// Inserts a word into the trie.
public void insert(String word) {
TrieNode node = root;
for (int i = 0; i < word.length(); i++) {
char currentChar = word.charAt(i);
if (!node.containsKey(currentChar)) {
node.put(currentChar, new TrieNode());
}
node = node.get(currentChar);
}
node.setEnd();
}
}
複製代碼
複雜度分析:cdn
(2)在trie中搜索關鍵詞
每個關鍵詞在trie中均可以被一條從根節點到子節點的路徑所表示。咱們將根據關鍵詞的第一個字母從根節點開始搜索,而後檢查節點上的每個鏈接對應的字母,通常有兩種狀況:
class Trie {
...
// search a prefix or whole key in trie and
// returns the node where search ends
private TrieNode searchPrefix(String word) {
TrieNode node = root;
for (int i = 0; i < word.length(); i++) {
char curLetter = word.charAt(i);
if (node.containsKey(curLetter)) {
node = node.get(curLetter);
} else {
return null;
}
}
return node;
}
// Returns if the word is in the trie.
public boolean search(String word) {
TrieNode node = searchPrefix(word);
return node != null && node.isEnd();
}
}
複製代碼
複雜度分析:
(3)在trie中搜索關鍵詞的前綴
這個方法和咱們在trie中用來搜索關鍵詞的方法很相似。咱們從根節點開始移動,直到關鍵詞前綴的每一個字母都被搜索到了,或者,沒有辦法在trie中根據關鍵詞的當前字母找到接下去的路徑。這個方法和前面提到的搜索關鍵詞的惟一不一樣在於,當咱們遍歷到關鍵詞前綴的最後一個字母時,咱們老是返回true,咱們不須要考慮當前的節點是否有結束標誌,由於咱們只是搜索關鍵詞的前綴,而不是整個關鍵詞。
class Trie {
...
// Returns if there is any word in the trie
// that starts with the given prefix.
public boolean startsWith(String prefix) {
TrieNode node = searchPrefix(prefix);
return node != null;
}
}
複製代碼
複雜度分析:
3. 應用問題
這裏有一些很是合適應你們去練習的問題,這些問題都能用trie數據結構解決。
這篇分析出自@elmirap