字典樹
首先看下百度百科的定義.
字典樹 是一種樹形結構,是一種哈希樹的變種。典型應用是用於統計,排序和保存大量的字符串(但不僅限於字符串),所以經常被搜索引擎系統用於文本詞頻統計。它的優點是:利用字符串的公共前綴來減少查詢時間,最大限度地減少無謂的字符串比較,查詢效率比哈希樹高。 —— [百度百科 ]
一個典型的字典樹可以如上圖所示。
字典樹的性質
字典樹主要有以下性質:
- 根結點不包含字符
- 每個節點的所有子節點包含字符不相同
- 根節點到某一節點,路徑上經過的所有字符拼起來,爲該節點對應的字符串
字典樹的實現
數據結構
根據上面的思路我可以簡單清晰的定義出字典樹的數據結構,如下:
class TrieNode
{
public:
TrieNode *next[26];
bool is_word;
int num;
TrieNode(bool b = false)
{
memset(next, 0, sizeof(next));
is_word = b;
num=0;
}
};
num可以方便的統計該節點表示的字符串出現的次數(頻率),這個直接在構建字典樹的過程中就可以實現;is_word用來標示該節點表示的字符串是一個完整的單詞還是僅是一個單詞的前綴;next數組用來存儲該節點的子節點。
字典樹的構建
void build(string s)
{
TrieNode *p = root;
for(int i=0;i<s.size();i++)
{
temp = s[i]-'a';
if(p->child[temp] == NULL)//判斷是否存在對應的子節點
{
p->child[temp] = new TrieNode();
}
p = p->child[temp];
p->num ++;
}
p -> is_word = true;//標示是一個單詞
}
創建的思路很簡單,每來一個單詞,便將單詞插入到已有的字典樹中,途中記錄詞頻數,插入完成後,記得將單詞標示設置爲true。給定單詞集:A,B,C,BD,BE,BF。將創建出如上圖所示的字典樹。
字典樹的使用
字典樹最常見的操作就是給定一個新的單詞,查找該單詞是否在字典樹中,返回他的詞頻(搜索引擎的詞頻統計);或者查找是否有以該單詞爲前綴的字符串。
TrieNode* find(string key)//根據輸入單詞返回對應的節點
{
TrieNode *p = root;
for(int i = 0; i < key.size() && p != NULL; ++ i)
p = p -> next[key[i] - 'a'];
return p;
}
// 返回該單詞是否在字典樹中
bool search(string key)
{
TrieNode *p = find(key);
return p != NULL && p -> is_word;
}
//返回詞頻
int search(string key)
{
TrieNode *p = find(key);
return (p != NULL && p -> is_word) ? p->num : 0;
}
//返回是否有以該單詞爲前綴的字符串
bool startsWith(string prefix)
{
return find(prefix) != NULL;
}
上述操作中find(查找)是核心方法,每次都是從根節點開始搜索,取要查找單詞的第一個字母,根據該字母選擇對應的子節點(樹)並轉到該子樹繼續進行搜索,這樣一直迭代下去,最終會返回表示該單詞的節點或者NULL(不存在這個單詞)。
字典樹的結構以及實現不難,自己通過簡單的代碼編寫就可以掌握。除了搜索引擎的詞頻統計,字典樹的具體應用也是多變的,之前在leetcode上看到過一個跟字典樹相關的題目,之後會補充到博客中。