###### tags: `LeetCode` `Medium` `Trie` `Object Oriented` `Tree` # LeetCode #208 [Implement Trie (Prefix Tree)](https://leetcode.com/problems/implement-trie-prefix-tree/) ### (Medium) Trie(發音類似 "try")或者說 前綴樹 是一種樹形數據結構,用於高效地存儲和檢索字符串數據集中的鍵。這一數據結構有相當多的應用情景,例如自動補完和拼寫檢查。 請你實現 Trie 類: Trie() 初始化前綴樹對象。 void insert(String word) 向前綴樹中插入字符串 word 。 boolean search(String word) 如果字符串 word 在前綴樹中,返回 true(即,在檢索之前已經插入);否則,返回 false 。 boolean startsWith(String prefix) 如果之前已經插入的字符串 word 的前綴之一為 prefix ,返回 true ;否則,返回 false 。 --- 目標為建構Trie類別。 首先先建構TrieNode類別, 該類別有兩個成員變數 1. bool is_word: 用於確認該節點為某個單字的結尾字元 2. vector<TrieNode*> children: 大小為26, 代表接在節點後的26個英文字母 再來做建構函式, 初始化is_word的值為false, 初始化宣告children。 再來做解構函式, 刪除所有子節點。 TrieNode有一個成員函式find, 輸入參數為const string&, 回傳型態為const TrieNode*, 函式內部不應該有任何修改。函式邏輯為, 讀入一個字元, 把它減去'a'的值作為索引找到children中的下一個節點, 如此反覆直到讀完全部的字元, 此時回傳指標。若途中指標為空指標, 代表指向的地方沒有被賦予值, 這代表之前沒有單字輸入, 所以找不到, 回傳空指標。 再來看到Trie類別: Trie類別有一個成員變數: root_, 為unique_ptr, 在離開函數時會自動刪除, 因此Trie物件不需要寫解構元。 Tire物件的建構函式: 建立TrieNode類別的物件root_, 並呼叫TrieNode()建構函式進行初始化。 Trie物件的insert成員函式: 從root_節點開始, 讀入每一個word中的字元, 若節點不存在, 則建立節點再將指標指向節點; 若存在則直接更改指標指向節點, 最後在遍歷完整個word後, 將指標處的is_word改為true, 代表此節點為某個單字的終點。 Trie物件的search成員函式: 呼叫之前建立的TrieNode的find函式, find函式會回傳一個指標, 檢查指標是否為空指標, 以及指標的is_word是否為true, 若皆為true, 代表該單字存在。 Trie物件的startsWith成員函式: 與search類似, 但條件較為寬鬆, 輸入的字串不需要為單字(單字的節點的is_word為true), 只要確認開頭相等就好, 因此調用TrieNode的find函式, 並確認回傳指標是否為空指標即可。 --- ``` class Trie { public: unique_ptr<TrieNode> root_; Trie():root_(new TrieNode()){} void insert(const string& word) { TrieNode* p = root_.get(); for(auto c:word){ if(!p->children[c-'a'])//not exist p->children[c-'a'] = new TrieNode(); p=p->children[c-'a']; } p->is_word = true; } bool search(const string& word) { const TrieNode* p = find(word); return p&&p->is_word; } bool startsWith(const string& prefix) { return find(prefix)!=nullptr; } private: struct TrieNode{ bool is_word; vector<TrieNode*> children; TrieNode():is_word(false), children(26, nullptr){} ~TrieNode(){ for(auto c:children) if(c)delete c; } }; const TrieNode* find(const string& word) const{ TrieNode* p = root_.get(); for(auto c:word){ p=p->children[c-'a']; if(!p)return nullptr; } return p; } }; ```