一个通用的Trie树,标准C++实现
来源:互联网 发布:自己拍婚纱照 知乎 编辑:程序博客网 时间:2024/06/05 13:21
Trie简介
Trie树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
在本文中,对于输入的进行序列化,比如输入“单词查找树”,序列化为“单/词/查/找/树”,这样可以进行任何一种自定义的数据插入和查询。序列化输入可以根据自己的需要进行相应的改动,这样可以把Trie树结构应用到很多其他的语言和领域。
本Trie树结构的优点在于:
1 不限制子节点的数量;
2 自定义的输入序列化,突破了具体语言、应用的限制,成为一个通用的框架;
3 可以进行最大Tokens序列长度的限制;
4 根据已定阈值输出重复的字符串;
5 提供单个字符串频度查找功能;
6 速度快,在两分钟内完成1998年1月份人民日报(19056行)的重复字符串抽取工作。
2 结构示意图
3 实现代码
Trie.h
- /********************************************************************
- * Copyright (C) 2012 Li Yachao
- * Contact: liyc7711@gmail.com or harry_lyc@foxmail.com
- *
- * Permission to use, copy, modify, and distribute this software for
- * any non-commercial purpose is hereby granted without fee, provided
- * that the above copyright notice appear in all copies and that both
- * that copyright notice.
- * It is provided "as is" without express or implied warranty.
- * http://www.linuxidc.com
- * Version: 0.1
- * Last update: 2012-4-2
- *********************************************************************/
- /*********************************************************************
- *********************************************************************/
- #ifndef TRIE_H
- #define TRIE_H
- #include <iostream>
- #include <fstream>
- #include <string>
- #include <vector>
- #include <stdio.h>
- namespace MyUtility
- {
- /*用于存储原子数据的数据结构*/
- typedef struct TrieNode
- {
- char* token;/*Trie节点的token值*/
- bool terminal;/*当前节点是否是终结点*/
- struct TrieNode* sons;/*子节点*/
- struct TrieNode* next;/*兄弟节点*/
- }TrieNode;
- /*输出结果的数据结构*/
- typedef struct StrFreq
- {
- std::string Str;/*字符串*/
- int Freq;/*频率*/
- }StrFreq;
- class Trie
- {
- public:
- Trie()
- {
- CreateRoot();
- travel_path.clear();
- result.clear();
- threshhold = 3;
- maxLength = 9 ;
- fout.open("result.txt");
- }
- ~Trie()
- {
- Destroy();
- }
- /*设置输出重复字符串频率的阈值*/
- void SetThreshhold(int ts)
- {
- if(ts<=1)
- {
- return ;
- }
- threshhold = ts;
- }
- /*设置最长的字符串匹配长度的阈值*/
- void SetMaxLength(int max_leng)
- {
- if(max_leng <= 1)
- {
- return ;
- }
- maxLength = max_leng;
- }
- /*输出结果*/
- void Print(std::vector<StrFreq>& result);
- void Print();
- bool AddString(const std::string& str);
- /*取得一个字符串的重复频率*/
- int StrFrequency(const char* str);
- /*清空Trie树*/
- bool Clear();
- private:
- std::ofstream fout;
- TrieNode * Root;/*Trie树根节点*/
- std::vector<std::string>travel_path;/*遍历是的访问路径*/
- std::vector<StrFreq>result;/*重复字符串的输出结果*/
- int sub_sons;/*一个节点的子节点数量*/
- int threshhold;/*重复字符串输出阈值,默认为2*/
- int maxLength;/*最长的Tokens序列长度,默认为9*/
- void Tokenize(const std::string& str,std::vector<std::string>&vec_tokens);
- TrieNode * InsertNode(TrieNode* node,const char *token,bool end = false);
- /*查找一个节点是否有子节点值为token的节点,返回子节点的指针*/
- TrieNode * FindNode(TrieNode* p_node,const char *token);
- /*初始化一个新的Trie节点*/
- inline TrieNode* NewNode()
- {
- TrieNode * newNode = new TrieNode();
- newNode->sons = NULL;
- newNode->next = NULL;
- newNode->token = NULL;
- newNode->terminal = false;
- return newNode;
- }
- /*初始化一个新的Trie树根节点*/
- void CreateRoot()
- {
- if( NULL != Root)
- {
- delete Root;
- Root = NULL;
- }
- Root = NewNode();
- char * root_tag ="Root";
- Root->token = new char[sizeof(char)*strlen(root_tag)];
- strcpy(Root->token,root_tag);
- }
- /*销毁Trie树*/
- void Destroy();
- /*销毁Trie子树*/
- void Destroy(TrieNode * node);
- /*遍历树结构*/
- void Travel(TrieNode* node);
- /*取得一个节点的子节点数*/
- void TrieNodeSons(const TrieNode* node);
- void TrieNodeSons(const TrieNode* node,const TrieNode* root);
- };
- }
- #endif
- #include "Trie.h"
- namespace MyUtility
- {
- /*
- *************************************************
- 功能 : 中文文本预处理,序列化输入
- 参数 :
- 返回值 :
- -------------------------------------------------
- 备注 :
- -------------------------------------------------
- 作者 :Li Yachao
- 时间 :2012-4-3
- *************************************************
- */
- void Trie::Tokenize(const std::string &str, std::vector<std::string> &vec_tokens)
- {
- vec_tokens.clear();
- std::string tmp ="";
- if(str.empty())
- {
- return ;
- }
- for(int i=0;i<str.size();i++)
- {
- unsigned char c = str[i];
- if(c < 128)
- {
- tmp = str.substr(i,1);
- vec_tokens.push_back(tmp);
- }
- else
- {
- tmp = str.substr(i,2);
- vec_tokens.push_back(tmp);
- i++;
- }
- }
- }
- /*
- *************************************************
- 功能 : 销毁Trie树
- 参数 :
- 返回值 :
- -------------------------------------------------
- 备注 :
- -------------------------------------------------
- 作者 :Li Yachao
- 时间 :2012-4-3
- *************************************************
- */
- void Trie::Destroy()
- {
- Destroy(Root);
- }
- void Trie::Destroy(TrieNode * node)
- {
- if(NULL != node)
- {
- Destroy(node->sons);
- Destroy(node->next);
- delete node;
- node = NULL;
- }
- else
- {
- return ;
- }
- }
- /*
- *************************************************
- 功能 : 清空Trie树
- 参数 :
- 返回值 :
- -------------------------------------------------
- 备注 :
- -------------------------------------------------
- 作者 :Li Yachao
- 时间 :2012-4-3
- *************************************************
- */
- bool Trie::Clear()
- {
- Destroy();
- CreateRoot();
- travel_path.clear();
- result.clear();
- return true;
- }
- /*
- *************************************************
- 功能 : 取得一个Trie数节点的子节点数,即一个Token序列的重复次数。
- 参数 :
- 返回值 :
- -------------------------------------------------
- 备注 :
- -------------------------------------------------
- 作者 :Li Yachao
- 时间 :2012-4-3
- *************************************************
- */
- void Trie::TrieNodeSons(const TrieNode * node,const TrieNode* root)
- {
- if(NULL != node)
- {
- TrieNodeSons(node->sons,root);
- if(node->terminal)
- {
- sub_sons++;/*以Token序列是否是序列结尾为标志*/
- }
- if(node != root)
- {/*根节点不能遍历其兄弟节点*/
- TrieNodeSons(node->next,root);
- }
- }
- else
- {
- return ;
- }
- }
- /*void Trie::TrieNodeSons(const TrieNode * node)
- {
- if(NULL != node)
- {
- TrieNodeSons(node->sons);
- if(node->terminal)
- {
- sub_sons++;
- }
- if(node != Root)
- {
- TrieNodeSons(node->next);
- }
- }
- else
- {
- return ;
- }
- }*/
- /*
- *************************************************
- 功能 : 遍历Trie数所有的节点,根据设定的threashold输出Token序列
- 参数 :
- 返回值 :
- -------------------------------------------------
- 备注 :
- -------------------------------------------------
- 作者 :Li Yachao
- 时间 :2012-4-3
- *************************************************
- */
- void Trie::Travel(TrieNode* node)
- {
- if(NULL != node)
- {
- if(node != Root)
- travel_path.push_back(node->token);
- Travel(node->sons);
- /********************************************************/
- sub_sons =0;
- //TrieNodeSons(node);
- TrieNodeSons(node,node);
- int sum = sub_sons;
- //sub_sons = 0;
- //TrieNodeSons(node->sons,node->sons);
- if((sub_sons >= threshhold))
- //if((sum != sub_sons) && (sum >= threshhold))
- {
- std::string buf="";
- for(int i=0;i<travel_path.size();i++)
- {
- buf += travel_path[i];
- }
- if(!buf.empty())
- {
- //fout<<buf<<"\t"<<sum<<std::endl;
- fout<<buf<<"\t"<<sub_sons<<std::endl;
- }
- }
- if(travel_path.size() > 0)
- {
- travel_path.pop_back();
- }
- /********************************************************/
- Travel(node->next);
- /********************************************************/
- /********************************************************/
- }
- else
- {
- return ;
- }
- }
- void Trie::Print()
- {
- travel_path.clear();
- result.clear();
- Travel(Root);
- std::cout<<"String\tFrequency"<<std::endl;
- for(int i=0;i<result.size();i++)
- {
- std::cout<<result[i].Str <<"\t"<<result[i].Freq <<std::endl;
- }
- result.clear();
- }
- void Trie::Print(std::vector<StrFreq>& re_result)
- {
- travel_path.clear();
- result.clear();
- Travel(Root);
- //re_result = result;
- //result.clear();
- }
- /*
- *************************************************
- 功能 : 输入Trie树字符串
- 参数 :
- 返回值 :
- -------------------------------------------------
- 备注 :
- -------------------------------------------------
- 作者 :Li Yachao
- 时间 :2012-4-3
- *************************************************
- */
- bool Trie::AddString(const std::string &str)
- {
- std::vector<std::string>val;
- std::vector<std::string>val_tmp;
- Tokenize(str,val);
- int step = maxLength;
- for(int i=0;i<val.size();i++)
- {
- val_tmp.clear();
- while((i+step) > val.size())
- {
- step --;
- }
- for(int j=i;j< (i+step);j++)
- {
- val_tmp.push_back(val[j]);
- }
- TrieNode* cur = Root;
- for(int j=0;j<val_tmp.size();j++)
- {
- if(j == val_tmp.size() - 1)
- {
- InsertNode(cur,val_tmp[j].c_str(),true);
- }
- else
- {
- cur = InsertNode(cur,val_tmp[j].c_str());
- }
- }
- }
- return true;
- }
- /*
- *************************************************
- 功能 : 插入Trie树节点
- 参数 :
- 返回值 : 插入节点的指针
- -------------------------------------------------
- 备注 :
- -------------------------------------------------
- 作者 :Li Yachao
- 时间 :2012-4-3
- *************************************************
- */
- TrieNode * Trie::InsertNode(TrieNode* node,const char *token,bool end)
- {
- if(NULL == node)
- {
- return NULL;
- }
- if(NULL == node->sons)
- {
- node->sons = NewNode();
- node->sons->token = new char[sizeof(char)*strlen(token)];
- strcpy(node->sons->token,token);
- if(end)
- {
- node->sons->terminal = true;
- }
- return node->sons;
- }
- else
- {
- TrieNode* cur = node->sons;
- while(NULL != cur->next)
- {
- if(strcmp(cur->token,token) == 0)
- {
- if(end)
- {
- cur->terminal = true;
- }
- return cur ;
- }
- if( NULL != cur->next)
- {
- cur = cur->next ;
- }
- else
- {
- break;
- }
- }
- if(strcmp(cur->token ,token) == 0)
- {
- if(end)
- {
- cur->terminal = true;
- }
- return cur;
- }
- TrieNode* n = NewNode();
- n->token = new char[sizeof(char)*strlen(token)];
- strcpy(n->token ,token);
- if(end)
- {
- n->terminal = true;
- }
- cur->next = n;
- return n;
- }
- }
- /*
- *************************************************
- 功能 : 查找一个字符串的重复次数
- 参数 :
- 返回值 :
- -------------------------------------------------
- 备注 :
- -------------------------------------------------
- 作者 :Li Yachao
- 时间 :2012-4-3
- *************************************************
- */
- int Trie::StrFrequency(const char* str)
- {
- std::vector<std::string>tokens;
- Tokenize(str,tokens);
- TrieNode * cur = Root;
- for(int i=0;i<tokens.size();i++)
- {
- cur = FindNode(cur,tokens[i].c_str());
- }
- if(NULL == cur)
- {
- return 0;
- }
- else
- {
- sub_sons =0;
- TrieNodeSons(cur, cur);
- return sub_sons;
- }
- }
- /*
- *************************************************
- 功能 : 查找一个节点的指针
- 参数 :
- 返回值 :
- -------------------------------------------------
- 备注 :
- -------------------------------------------------
- 作者 :Li Yachao
- 时间 :2012-4-3
- *************************************************
- */
- TrieNode * Trie::FindNode(TrieNode *p_node, const char *token)
- {
- if((NULL != p_node) && (NULL != p_node->sons))
- {
- TrieNode *cur = p_node->sons;
- while(NULL != cur)
- {
- if(strcmp(cur->token,token) == 0)
- {
- return cur;
- }
- cur = cur->next;
- }
- return NULL;
- }
- else
- {
- return NULL;
- }
- }
- }
- 一个通用的Trie树,标准C++实现
- 一个通用的Trie树,标准C++实现
- 一个通用的Trie树,标准C++实现
- 标准trie树的Java实现
- 一个Trie树的实现
- Trie的一个实现
- 一个Trie字典树的简单实现
- 一个简单的Trie树实现
- 一个Trie树的简单实现
- 一个通用纯C队列的实现
- Trie 前缀树的c 实现
- Trie树的实现
- Trie树的实现
- 嵌入式(标准C环境下)下通用的内存池的实现---C文件
- 一个.NET通用JSON解析/构建类的实现(c#)
- 一个.NET通用JSON解析/构建类的实现(c#)
- 一个.NET通用JSON解析/构建类的实现(c#)
- c语言实现一个简单的通用动态数组
- 深入理解http响应拆分
- HQL调用自定义函数
- 如何完全退出单例模式下的android应用程序,非常好用
- DIECTOR中如何调用控制面板中的各种设置窗口及系统控制
- 回溯法计算总费用最小费用
- 一个通用的Trie树,标准C++实现
- MFC部分默认资源详解笔记
- hdu1059 Dividing 搜索
- 自己经常忘记的代码
- qt隐藏鼠标方法汇总
- 设计模式总结
- 由自定义的拦截器窥探struts2 Interceptor拦截器拦截机制
- 怎么解决svn error "svn: Aborting commit: xxx remains in conflict"?
- 备份恢复3——用户管理的备份与恢复*