Trie(prefix tree)
阿新 • • 發佈:2020-11-17
Trie
Trie 是一種特殊的資料結構,與二叉樹類似,只是 Trie 不限子孩子數量。
Trie 又名字典樹,單詞查詢樹,字首樹。我們可以使用 Trie 來構造工作中使用到的 紅點系統 。
下面以 LeetCode 的第208題 Implement Trie (Prefix Tree) 來討論實現 Trie 這種特殊的資料結構。
題目描述
Implement a trie with insert, search, and startsWith methods.
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.search("app"); // returns true
Note: You may assume that all inputs are consist of lowercase letters a-z.All inputs are guaranteed to be non-empty strings.
實現 Trie
假設我們要往 Trie 中加入 ['apple', 'app', 'about', 'bed']。
在建立 Trie 時,我們以物件 Object 為儲存型別,對一個單詞字母都是物件的一個屬性,然後在每個單詞末尾時,我們加多一個單詞結尾標識 isEnd。
把對應的單詞插入 Trie 後,我們將得到下圖所示的 Trie 結構:
1. 插入單詞
插入單詞時,每一個字母對應一個結點物件,如果沒有對應的結點則建立;如果有就在此結點下繼續查詢。在單詞的結尾時,我們需加入單詞結束標識 isEnd,以便查詢。
let obj = this.root;
for (let i = 0; i < word.length; i++) {
let c = word[i];
// 沒有這個字母結點,建立
if (!obj[c]) {
obj[c] = {};
}
obj = obj[c];
}
// 標識單詞結尾
obj.isEnd = true;
2. 查詢單詞或字首
在查詢單詞或字首的時候,需要一步一步的往下查詢,如果中途沒有任一個結點,則直接返回即可。如果是查詢單詞,找到了對應的最後一個字母結點後,我們仍需判斷結點是否有 isEnd
// 查詢函式
Trie.prototype.commonSearch = function (word) {
let obj = this.root;
for (let char of word.split('')) {
if (!obj[char]) {
// 對應對應字母的結點,返回null
return null;
} else {
obj = obj[char];
}
}
// 找到最後一個單詞結點,返回結點物件
return obj;
};
完整程式碼附下
/**
* Initialize your data structure here.
*/
const Trie = function () {
this.root = {};
};
/**
* Inserts a word into the trie.
* @param {string} word
* @return {void}
*/
Trie.prototype.insert = function (word) {
let obj = this.root;
for (let i = 0; i < word.length; i++) {
let c = word[i];
if (!obj[c]) {
obj[c] = {};
}
obj = obj[c];
}
obj.isEnd = true;
};
/**
* Returns if the word is in the trie.
* @param {string} word
* @return {boolean}
*/
Trie.prototype.search = function (word) {
let obj = this.commonSearch(word);
return obj && obj.isEnd ? true : false;
};
/**
* Returns if there is any word in the trie that starts with the given prefix.
* @param {string} prefix
* @return {boolean}
*/
Trie.prototype.startsWith = function (prefix) {
let obj = this.commonSearch(prefix);
return !!obj;
};
/**
* @param {string} prefix
* @return {any}
*/
Trie.prototype.commonSearch = function (word) {
let obj = this.root;
for (let char of word.split('')) {
if (!obj[char]) {
return null;
} else {
obj = obj[char];
}
}
return obj;
};