Trie字典樹算法

特性

Trie樹屬於樹形結構,查詢效率比紅黑樹和哈希表都要快。假設有這麼一種應用場景:有若干個英文單詞,須要快速查找某個單詞是否存在於字典中。使用Trie時先從根節點開始查找,直至匹配到給出字符串的最後一個節點。在創建字典樹結構時,預先把帶有相同前綴的單詞合併在同一節點,直至兩個單詞的某一個字母不一樣,則再從發生差別的節點中分叉一個子節點。html

節點結構:
每一個節點對應一個最大可儲存字符數組。假設字典只存26個小寫英文字母,那麼每一個節點下應該有一個長度爲26的數組。換言說,可存的元素類型越多,單個節點佔用內存越大。若是用字典樹儲存漢字,那麼每一個節點必須爲數千個經常使用漢字開闢一個數組做爲儲存空間,佔用的內存實在不是一個數量級。不過Trie樹就是一種用空間換時間的數據結構,魚和熊掌每每不可兼得。node

建樹細節:數組

  • 取要插入字符串的首個字符,從根節點的孩子節點開始,匹配當前字符是否已有節點,有則把指針指向該節點。無則爲該字符建立節點,並把指針指向該新建節點。
  • 迭代。
  • 遇到要插入字符串末尾結束符時中止迭代,並把最後一個非’\0′字符對應的節點設爲末端節點。

查找細節:
循環取要插入字符串的首個字符,從根節點的孩子節點開始,匹配當前字符是否已有節點,有則繼續循環,無則返回False. 直至匹配到最後一個字符則完成查找。數據結構

樹結構圖:
咱們用apps, apply, apple, append, back, basic, backen幾英文單詞建立樹形結構:
trieapp

上圖很容易看出,有相同前綴的英文單詞,會合並在同一個節點,Trie樹順着一個個節點進行檢索,直至找到最後一個節點。代碼以下:spa

 1 #include <stdio.h>
 2  
 3 struct trie_node
 4 {
 5     static const int letter_count = 26;
 6  
 7     int count;
 8     bool is_terminal;
 9     char letter;
10     trie_node* childs[letter_count];
11  
12     trie_node()
13         : letter(0), count(1), is_terminal(false)
14     {
15         for (int i = 0; i < letter_count; ++i)
16             childs[i] = NULL;
17     }
18 };
19  
20 class trie
21 {
22 public:
23     trie()
24         : root_node_(NULL)
25     {
26     }
27  
28     ~trie()
29     {
30         delete_trie(root_node_);
31     }
32  
33 public:
34     trie_node* create()
35     {
36         trie_node* n = new trie_node();
37         return n;
38     }
39  
40     void insert(const char* str)
41     {
42         if (!root_node_ || !str)
43             root_node_ = create();
44  
45         trie_node* next_element_node = root_node_;
46         while (*str != 0)
47         {
48             char element_index = *str - 'a';
49             if (!next_element_node->childs[element_index])
50             {
51                 next_element_node->childs[element_index] = create();
52             }
53             else
54             {
55                 next_element_node->childs[element_index]->count++;
56             }
57  
58             next_element_node = next_element_node->childs[element_index];
59             next_element_node->letter = *str;
60             str++;
61         }
62  
63         next_element_node->is_terminal = true;
64     }
65  
66     bool find_word_exists(const char* str)
67     {
68         if (!root_node_ || !str)
69             return NULL;
70  
71         trie_node* element_node = root_node_;
72         do
73         {
74             element_node = element_node->childs[*str - 'a'];
75             if (!element_node) return false;
76             str++;
77         } while (*str != 0);
78  
79         return element_node->is_terminal;
80     }
81  
82     void delete_trie(trie_node* node)
83     {
84         if (!node) return;
85         for(int i = 0; i < trie_node::letter_count; i++)
86         {
87             if(node->childs[i] != NULL)
88                 delete_trie(node->childs[i]);
89         }
90  
91         delete node;
92     }
93  
94 private:
95     trie_node* root_node_;
96 };

轉:http://powman.org/archives/trie.html指針

相關文章
相關標籤/搜索