Trie树的C++实现

来源:互联网 发布:耻辱2盗版优化补丁 编辑:程序博客网 时间:2024/06/05 17:41

Trie—单词查找树

Trie,又称单词查找树、前缀树,是一种哈希树的变种。应用于字符串的统计与排序,经常被搜索引擎系统用于文本词频统计。

性质:
1.根节点不包含字符,除根节点外的每一个节点都只包含一个字符。
2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
3.每个节点的所有子节点包含的字符都不相同。

优点:
1.查询快。对于长度为m的键值,最坏情况下只需花费O(m)的时间;而BST需要O(m log n)的时间。
2.当存储大量字符串时,Trie耗费的空间较少。因为键值并非显式存储的,而是与其他键值共享子串。

操作:
1.初始化或清空:遍历Trie,删除所有节点,只保留根节点。

2.插入字符串
1).设置当前节点为根节点,设置当前字符为插入字符串中的首个字符;
2).在当前节点的子节点上搜索当前字符,若存在,则将当前节点设为值为当前字符的子节点;否则新建一个值为当前字符的子节点,并将当前结点设置为新创建的节点。
3).将当前字符设置为串中的下个字符,若当前字符为0,则结束;否则转2.

3.查找字符串
搜索过程与插入操作类似,当字符找不到匹配时返回假;若全部字符都存在匹配,判断最终停留的节点是否为树叶,若是,则返回真,否则返回假。

4.删除字符串
首先查找该字符串,边查询边将经过的节点压栈,若找不到,则返回假;否则依次判断栈顶节点是否为树叶,若是则删除该节点,否则返回真。

[cpp] view plaincopy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. /* trie的节点类型 */  
  5. template <int Size> //Size为字符表的大小  
  6. struct trie_node   
  7. {  
  8.     bool terminable; //当前节点是否可以作为字符串的结尾  
  9.     int node; //子节点的个数  
  10.     trie_node *child[Size]; //指向子节点指针  
  11.   
  12.     /* 构造函数 */  
  13.     trie_node() : terminable(false), node(0) { memset(child, 0, sizeof(child)); }  
  14. };  
  15.   
  16. /* trie */  
  17. template <int Size, typename Index> //Size为字符表的大小,Index为字符表的哈希函数  
  18. class trie   
  19. {  
  20. public:  
  21.     /* 定义类型别名 */  
  22.     typedef trie_node<Size> node_type;  
  23.     typedef trie_node<Size>* link_type;  
  24.   
  25.     /* 构造函数 */  
  26.     trie(Index i = Index()) : index(i){ }  
  27.   
  28.     /* 析构函数 */  
  29.     ~trie() { clear(); }  
  30.   
  31.     /* 清空 */  
  32.     void clear()   
  33.     {  
  34.         clear_node(root);  
  35.         for (int i = 0; i < Size; ++i)  
  36.             root.child[i] = 0;  
  37.     }  
  38.   
  39.     /* 插入字符串 */  
  40.     template <typename Iterator>  
  41.     void insert(Iterator begin, Iterator end)   
  42.     {  
  43.         link_type cur = &root; //当前节点设置为根节点  
  44.         for (; begin != end; ++begin)   
  45.         {  
  46.             if (!cur->child[index[*begin]]) //若当前字符找不到匹配,则新建节点  
  47.             {  
  48.                 cur->child[index[*begin]] = new node_type;  
  49.                 ++cur->node; //当前节点的子节点数加一  
  50.             }  
  51.             cur = cur->child[index[*begin]]; //将当前节点设置为当前字符对应的子节点  
  52.         }  
  53.         cur->terminable = true//设置存放最后一个字符的节点的可终止标志为真  
  54.     }  
  55.   
  56.     /* 插入字符串,针对C风格字符串的重载版本 */  
  57.     void insert(const char *str)  
  58.     {  
  59.         insert(str, str + strlen(str));   
  60.     }  
  61.   
  62.     /* 查找字符串,算法和插入类似 */  
  63.     template <typename Iterator>  
  64.     bool find(Iterator begin, Iterator end)   
  65.     {  
  66.         link_type cur = &root;  
  67.         for (; begin != end; ++begin)   
  68.         {  
  69.             if (!cur->child[index[*begin]])   
  70.                 return false;  
  71.             cur = cur->child[index[*begin]];  
  72.         }  
  73.         return cur->terminable;  
  74.     }  
  75.   
  76.     /* 查找字符串,针对C风格字符串的重载版本 */  
  77.     bool find(const char *str)   
  78.     {  
  79.         return find(str, str + strlen(str));   
  80.     }  
  81.   
  82.     /* 删除字符串 */  
  83.     template <typename Iterator>  
  84.     bool erase(Iterator begin, Iterator end)   
  85.     {  
  86.         bool result; //用于存放搜索结果  
  87.         erase_node(begin, end, root, result);  
  88.         return result;  
  89.     }  
  90.   
  91.     /* 删除字符串,针对C风格字符串的重载版本 */  
  92.     bool erase(char *str)   
  93.     {      
  94.         return erase(str, str + strlen(str));   
  95.     }  
  96.   
  97.     /* 按字典序遍历单词树 */  
  98.     template <typename Functor>  
  99.     void traverse(Functor &execute = Functor())   
  100.     {  
  101.         visit_node(root, execute);  
  102.     }  
  103.   
  104. private:  
  105.     /* 访问某结点及其子结点 */  
  106.     template <typename Functor>  
  107.     void visit_node(node_type cur, Functor &execute)   
  108.     {  
  109.         execute(cur);  
  110.         for (int i = 0; i < Size; ++i)   
  111.         {  
  112.             if (cur.child[i] == 0) continue;  
  113.             visit_node(*cur.child[i], execute);  
  114.         }  
  115.     }  
  116.     /* 清除某个节点的所有子节点 */  
  117.     void clear_node(node_type cur)   
  118.     {  
  119.         for (int i = 0; i < Size; ++i)   
  120.         {  
  121.             if (cur.child[i] == 0) continue;  
  122.             clear_node(*cur.child[i]);  
  123.             delete cur.child[i];  
  124.             cur.child[i] = 0;  
  125.             if (--cur.node == 0) break;  
  126.         }  
  127.     }  
  128.   
  129.     /* 边搜索边删除冗余节点,返回值用于向其父节点声明是否该删除该节点 */  
  130.     template <typename Iterator>  
  131.     bool erase_node(Iterator begin, Iterator end, node_type &cur, bool &result)   
  132.     {  
  133.         if (begin == end) //当到达字符串结尾:递归的终止条件  
  134.         {   
  135.             result = cur.terminable; //如果当前节点可以作为终止字符,那么结果为真  
  136.             cur.terminable = false;  //设置该节点为不可作为终止字符,即删除该字符串  
  137.             return cur.node == 0;    //若该节点为树叶,那么通知其父节点删除它  
  138.         }  
  139.         //当无法匹配当前字符时,将结果设为假并返回假,即通知其父节点不要删除它  
  140.         if (cur.child[index[*begin]] == 0) return result = false;   
  141.         //判断是否应该删除该子节点  
  142.         else if (erase_node((++begin)--, end, *(cur.child[index[*begin]]), result))   
  143.         {   
  144.             delete cur.child[index[*begin]]; //删除该子节点  
  145.             cur.child[index[*begin]] = 0; //子节点数减一  
  146.             //若当前节点为树叶,那么通知其父节点删除它  
  147.             if (--cur.node == 0 && cur.terminable == falsereturn true;   
  148.         }  
  149.         return false//其他情况都返回假  
  150.     }  
  151.   
  152.     /* 根节点 */  
  153.     node_type root;  
  154.   
  155.     /* 将字符转换为索引的转换表或函数对象 */  
  156.     Index index;  
  157. };  
  158.   
  159. //index function object  
  160. class IndexClass  
  161. {    
  162. public:  
  163.     int operator[](const char key)    
  164.     {    
  165.         return key % 26;    
  166.     }  
  167. };  
  168.   
  169. int main()  
  170. {  
  171.     trie<26,IndexClass> t;  
  172.     t.insert("tree");  
  173.     t.insert("tea");  
  174.     t.insert("A");  
  175.     t.insert("ABC");  
  176.   
  177.     if(t.find("tree"))  
  178.         cout<<"find tree"<<endl;  
  179.     else  
  180.         cout<<"not find tree"<<endl;  
  181.   
  182.     if(t.find("tre"))  
  183.         cout<<"find tre"<<endl;  
  184.     else  
  185.         cout<<"not find tre"<<endl;  
  186.       
  187.     if(t.erase("tree"))  
  188.         cout<<"delete tree"<<endl;  
  189.     else  
  190.         cout<<"not find tree"<<endl;  
  191.   
  192.     if(t.find("tree"))  
  193.         cout<<"find tree"<<endl;  
  194.     else  
  195.         cout<<"not find tree"<<endl;  
  196.   
  197.     return 0;  
  198. }  
http://en.wikipedia.org/wiki/Trie
0 0