什么叫Trie树?

Trie树即字典树。

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。
(以上来自百度百科,点这里
在我看来,Trie树是一棵26叉树(如果是统计字母的话),典型的空间换时间。那到底我们利用Trie来做什么呢?
1.统计单词
2.匹配前缀
千篇一律地需要提到其性质:
1.根节点不包含字符,除根节点外的每一个子节点都只包含一个字符。
2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串
3.每个节点的所有子节点包含的字符都不相同。
而其效率主要体现,通过公共前缀尽可能减少查找复杂度。
 
下面,没拍过字典树的同学就跟着来练习吧!很快你就有感觉了。
首先,发一个模板,我是一个从开始学习语言就写C++的人,所以我用了模板+类来写,喜欢c风格的同学也可以看看其他人共享的模板。(感觉有点长~但是相对我觉得好理解,假设你知道并且喜欢用template.)
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
using namespace std;
template<int Size>
struct trie_node
{ bool terminable; //表示节点为字符串的结尾
int node; //子节点的个数
trie_node *child[Size]; //儿子节点
trie_node():terminable(false), node()
{
memset(child,,sizeof(child)); //初始化节点
} };
template<int Size,typename Index>
class trie
{
public:
//定义类名
typedef trie_node<Size> node_type;
typedef trie_node<Size> *link_type; //构造函数
trie(Index i=Index()):index(i) { } void clear() //清空函数,用于析构
{
clear_node(root);
for(int i=; i<Size; i++)
root.child[i]=;
}
template<typename Iterator>
void insert(Iterator begin,Iterator end) //插入
{
link_type cur= &root;//当前插入结点为根
while(begin!=end)
{
if(!cur->child[index[*begin]]) //没有插入过
{
cur->child[index[*begin]]=new node_type;
cur->node++; //插入后,父亲多了一个儿子
}
cur=cur->child[index[*begin]]; //搜儿子
begin++; //迭代器往前走!
}
cur->terminable=true; } void insert(const char * str) //重载c风格插入
{
insert(str,str+strlen(str));
} template <typename Iterator>
bool find(Iterator begin,Iterator end) //查找
{
link_type cur=&root;
while(begin!=end)
{ if(!cur->child[index[*begin]]) //没有节点啊!!!
return false;
cur=cur->child[index[*begin]]; //搜索儿子
begin++;
}
return cur->terminable; //是否为字符串
} bool find(const char *str) //重载c风格
{
return find(str,str+strlen(str));
} template<typename Iterator>
bool earse (Iterator begin,Iterator end) //删除字符串
{
bool result;
earse_node(begin,end,root,result);
return result;
} bool erase(char *str) //c语言风格
{
return earse(str,str+strlen(str)); } private: void clear_node(node_type cur) //清空
{
for(int i=; i<Size; i++)
{
if(cur.child[i]==)continue; //不存在
clear_node(*cur.child[i]);
delete cur.child[i];
cur.child[i]=;
if(--cur.node==) break; //没有节点了 } } //一边搜索一边删除
template<typename Iterator>
bool earse_node(Iterator begin ,Iterator end,node_type &cur,bool &result)
{
if(begin==end)
{
result=cur.terminable;
cur.terminalbe=false;
return cur.node==; }
//当孩子不存在,结果假,返回假
if(cur.child[index[*begin ]]==) return !(result=false);
else if(earse_node(begin+,end,*(cur.child[index[*begin]]),result))
{
delete cur.child[index[*begin]];
cur.child[index[*begin]]=;
if(--cur.node==&&cur.terminable==false ) return true; }
return false; }
//根
node_type root;
//字符转索引,类似hash
Index index; }; class IndexClass
{
public:
int operator[](const char key)
{
return key%; //一个映射 } }; int main()
{
trie<,IndexClass> t; //字母就是26,数字就是10
t.insert("tree"); //插入
t.insert("tea");
t.insert("act");
t.insert("adv");
t.insert("ate");
while(scanf("%s",str)!=EOF)//查找
{
if(t.find(str))
{
cout<<"find"<<endl;
} }
return ;
}

之后,怎么少得了经典的问题呢?

HDU1251(统计难题)

字典树做这些问题就是神器啊。注意统计的时候,node的处理,也就是insert和find的一些改变。
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
using namespace std;
template<int Size>
struct trie_node
{ bool terminable; //表示节点为字符串的结尾
int node; //子节点的个数
trie_node *child[Size]; //儿子节点
trie_node():terminable(false), node()
{
memset(child,,sizeof(child)); //初始化节点
} };
template<int Size,typename Index>
class trie
{
public:
//定义类名
typedef trie_node<Size> node_type;
typedef trie_node<Size> *link_type; //构造函数
trie(Index i=Index()):index(i) { } void clear() //清空函数,用于析构
{
clear_node(root);
for(int i=; i<Size; i++)
root.child[i]=;
}
//插入
template<typename Iterator>
void insert(Iterator begin,Iterator end){
link_type cur= &root;//当前插入结点为根
while(begin!=end){
if(cur->child[index[*begin]]){//插入过
cur=cur->child[index[*begin]];
++(cur->node); }else{
cur->child[index[*begin]]=new node_type; //这里这里!!!不一样!!!!
++(cur->child[index[*begin]]->node);
cur=cur->child[index[*begin]]; } begin++; //迭代器往前走!
}
cur->terminable=true; } void insert(const char * str) //重载c风格插入
{
insert(str,str+strlen(str));
} template <typename Iterator>
bool find(Iterator begin,Iterator end) //查找
{
link_type cur=&root;
while(begin!=end)
{ if(!cur->child[index[*begin]]) //没有节点啊!!!
return false;
cur=cur->child[index[*begin]]; //搜索儿子
begin++;
}
return cur->terminable; //是否为字符串
} bool find(const char *str) //重载c风格
{
return find(str,str+strlen(str));
}
template <typename Iterator>
int findNum(Iterator begin,Iterator end){
link_type cur=&root;
while(begin!=end){ if(!cur->child[index[*begin]]) //没有节点啊!!!
return ;
cur=cur->child[index[*begin]]; begin++; } return cur->node; //是否为字符串
}
//重载c风格
int findNum(const char *str){ return findNum(str,str+strlen(str));
} template<typename Iterator>
bool earse (Iterator begin,Iterator end) //删除字符串
{
bool result;
earse_node(begin,end,root,result);
return result;
} bool erase(char *str) //c语言风格
{
return earse(str,str+strlen(str)); } private: void clear_node(node_type cur) //清空
{
for(int i=; i<Size; i++)
{
if(cur.child[i]==)continue; //不存在
clear_node(*cur.child[i]);
delete cur.child[i];
cur.child[i]=;
if(--cur.node==) break; //没有节点了 } } //一边搜索一边删除
template<typename Iterator>
bool earse_node(Iterator begin ,Iterator end,node_type &cur,bool &result)
{
if(begin==end)
{
result=cur.terminable;
cur.terminalbe=false;
return cur.node==; }
//当孩子不存在,结果假,返回假
if(cur.child[index[*begin ]]==) return !(result=false);
else if(earse_node(begin+,end,*(cur.child[index[*begin]]),result))
{
delete cur.child[index[*begin]];
cur.child[index[*begin]]=;
if(--cur.node==&&cur.terminable==false ) return true; }
return false; }
//根
node_type root;
//字符转索引,类似hash
Index index; }; class IndexClass
{
public:
int operator[](const char key)
{
return key%; //一个映射 } }; int main(){
trie<,IndexClass> t;
char s[]; while(gets(s) && s[])
{
t.insert( s);
} while(gets(s))
{
printf("%d\n", t.findNum(s));
} return ; }

HDU1671

http://acm.hdu.edu.cn/showproblem.php?pid=1671

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<vector>
using namespace std;
#define MAXN 10
template<int Size>
struct trie_node
{ bool terminable; //表示节点为字符串的结尾
int node; //子节点的个数
trie_node *child[Size]; //儿子节点
trie_node():terminable(false), node()
{
memset(child,,sizeof(child)); //初始化节点
} };
template<int Size,typename Index>
class trie
{
public:
//定义类名
typedef trie_node<Size> node_type;
typedef trie_node<Size> *link_type; //构造函数
trie(Index i=Index()):index(i) { } //清空函数,用于析构
void clear()
{
clear_node(root);
for(int i=; i<Size; i++)
root.child[i]=;
}
//插入
template<typename Iterator>
void insert(Iterator begin,Iterator end)
{
link_type cur= &root;//当前插入结点为根
while(begin!=end)
{
if(cur->child[index[*begin]]) //插入过
{
cur=cur->child[index[*begin]];
cur->node++; }
else
{
cur->child[index[*begin]]=new node_type;
cur->child[index[*begin]]->node++;
cur=cur->child[index[*begin]]; }
begin++; //迭代器往前走!
}
cur->terminable=true; } //重载c风格插入
void insert(const char * str)
{
insert(str,str+strlen(str));
}
//插入
template<typename Iterator>
bool insert2(Iterator begin,Iterator end)
{
link_type cur= &root;//当前插入结点为根 bool flag=;
while(begin!=end)
{
if(cur->child[index[*begin]]) //插入过
{
if(cur->child[index[*begin]]->terminable==true){ flag=;
}
cur=cur->child[index[*begin]];
cur->node++; }
else
{
cur->child[index[*begin]]=new node_type;
cur->child[index[*begin]]->node++;
cur=cur->child[index[*begin]]; }
begin++; //迭代器往前走!
}
cur->terminable=true;
return flag; } //重载c风格插入
bool insert2(const char * str)
{
return insert2(str,str+strlen(str));
} //查找
template <typename Iterator>
bool find(Iterator begin,Iterator end)
{
link_type cur=&root;
while(begin!=end)
{ if(!cur->child[index[*begin]]) //没有节点啊!!!
return false;
cur=cur->child[index[*begin]]; begin++; }
return cur->terminable; //是否为字符串
}
//重载c风格
bool find(const char *str)
{ return find(str,str+strlen(str));
} //查找节点数目
template <typename Iterator>
int findNum(Iterator begin,Iterator end)
{
link_type cur=&root;
while(begin!=end)
{ if(!cur->child[index[*begin]]) //没有节点啊!!!
return ;
cur=cur->child[index[*begin]]; begin++; } return cur->node; //是否为字符串
}
//重载c风格
int findNum(const char *str)
{ return findNum(str,str+strlen(str));
} //查找前缀
template <typename Iterator>
bool findPre(Iterator begin,Iterator end)
{
link_type cur=&root;
while(begin!=end)
{ if(!cur->child[index[*begin]]) //没有节点啊!!!
return false; if(cur->terminable) break;
cur=cur->child[index[*begin]]; begin++; }
return begin!=end; //是否为字符串
} bool findPre(const char *str){
return findPre(str,str+strlen(str)); } //删除字符串
template<typename Iterator>
bool earse (Iterator begin,Iterator end)
{
bool result;
earse_node(begin,end,root,result);
return result; } //c语言风格
bool erase(char *str)
{
return earse(str,str+strlen(str)); } template<typename Functor>
void traverse(Functor &execute =Functor())
{
visit_node(root,execute); }
private:
//访问结点
template<typename Functor>
void visit_node(node_type cur,Functor &execute)
{
execute(cur);
for(int i=; i<Size; i++) //dfs
{
if(cur.child[i]==) continue;
visit_node(*cur.child[i],execute); }
} //清空
void clear_node(node_type cur)
{
for(int i=; i<Size; i++)
{
if(cur.child[i]==)continue; //不存在
clear_node(*cur.child[i]);
delete cur.child[i];
cur.child[i]=;
if(--cur.node==) break; //没有节点了 } } //一边搜索一边删除
template<typename Iterator>
bool earse_node(Iterator begin ,Iterator end,node_type &cur,bool &result)
{
if(begin==end)
{
result=cur.terminable;
cur.terminalbe=false;
return cur.node==; }
//当孩子不存在,结果假,返回假
if(cur.child[index[*begin ]]==) return !(result=false);
else if(earse_node(begin+,end,*(cur.child[index[*begin]]),result))
{
delete cur.child[index[*begin]];
cur.child[index[*begin]]=;
if(--cur.node==&&cur.terminable==false ) return true; }
return false; }
//根
node_type root; //字符转索引,类似hash
Index index; }; class IndexClass
{
public:
int operator[](const char key)
{
return key%MAXN; //一个映射 } }; char s[][];
int main()
{
trie<MAXN,IndexClass> t; int T,n,i;
// freopen("in.txt","r",stdin);
scanf("%d",&T); while(T--)
{
scanf("%d",&n); t.clear();
for(i=;i<n;i++){ scanf("%s",s[i]); t.insert(s[i]); }
for(i=;i<n;i++){ if(t.findPre(s[i])){ puts("NO");
break;
}
}
if(i==n) puts("YES"); } return ; }
 
HDU1004,或许你用map水过去了,但是你不妨试试用字典树获取0ms吧!
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
using namespace std;
template<int Size>
struct trie_node{ bool terminable; //???????????
int node; //??????
int cnt;
trie_node *child[Size]; //????
trie_node():terminable(false), node(),cnt(){
memset(child,,sizeof(child)); //?????
} };
int maxN;
char sb[];
char s[];
template<int Size,typename Index>
class trie{
public:
//????
typedef trie_node<Size> node_type;
typedef trie_node<Size> *link_type; //????
trie(Index i=Index()):index(i){ } //????,????
void clear(){
clear_node(root);
for(int i=;i<Size;i++)
root.child[i]=;
}
//??
template<typename Iterator>
bool insert(Iterator begin,Iterator end){
link_type cur= &root;//????????
while(begin!=end){
if(!cur->child[index[*begin]]){//??? cur->child[index[*begin]]=new node_type; cur->node++; }
cur=cur->child[index[*begin]]; begin++; //??????!
} cur->terminable=true;
cur->cnt++;
if(cur->cnt> maxN){
maxN=cur->cnt;
// cout<<maxN;
return true;
}
return false; } //??c????
void insert( char * str){
if(insert(str,str+strlen(str))){
strcpy(sb,str); };
} private: //??
void clear_node(node_type cur){
for(int i=;i<Size;i++){
if(cur.child[i]==)continue; //???
clear_node(*cur.child[i]);
delete cur.child[i];
cur.child[i]=;
if(--cur.node==) break; //????? } } //?
node_type root;
//?????,??hash
Index index; }; class IndexClass{
public:
int operator[](const char key){
return key%; //???? } }; int main(){
trie<,IndexClass> t; //freopen("in.txt","r",stdin);
int n;
while(scanf("%d",&n)&&n)
{ maxN=-;
for(int i=;i<n;i++){
scanf("%s",s); t.insert(s);
// cout<<maxN<<endl;
} printf("%s\n",sb);
t.clear();
} return ; }

HDU1075

http://acm.hdu.edu.cn/showproblem.php?pid=1075

这题目还是很赤裸的字典树,但是我犯了一个小错,让我WA无数次。
AC的:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
using namespace std;
char str1[];
char str2[];
char st[]; template<int Size>
struct trie_node
{ bool terminable; //表示节点为字符串的结尾
int node; //子节点的个数
char str[];
trie_node *child[Size]; //儿子节点
trie_node():terminable(false), node()
{
memset(child,,sizeof(child)); //初始化节点
} }; template<int Size,typename Index>
class trie
{
public:
//定义类名
typedef trie_node<Size> node_type;
typedef trie_node<Size> *link_type; //构造函数
trie(Index i=Index()):index(i) { } //清空函数,用于析构
void clear()
{
clear_node(root);
for(int i=; i<Size; i++)
root.child[i]=;
}
//插入
template<typename Iterator>
void insert(Iterator begin,Iterator end)
{
link_type cur= &root;//当前插入结点为根
while(begin!=end)
{
if(cur->child[index[*begin]]) //插入过
{
cur=cur->child[index[*begin]];
++(cur->node); }
else
{
cur->child[index[*begin]]=new node_type;
++(cur->child[index[*begin]]->node);
cur=cur->child[index[*begin]]; } begin++; //迭代器往前走!
}
cur->terminable=true;
int len=strlen(str1);
for(int i=; i<=len; i++)
cur->str[i]=str1[i]; } //重载c风格插入
void insert(const char * str)
{
insert(str,str+strlen(str));
} //查找
template <typename Iterator>
bool find(Iterator begin,Iterator end)
{
link_type cur=&root;
while(begin!=end)
{ if(!cur->child[index[*begin]]) //没有节点啊!!!
return false;
cur=cur->child[index[*begin]]; begin++; }
// printf("%s sb",cur->str);
if(cur->terminable)
{
printf("%s",cur->str);
return true; }
return false; //是否为字符串
} //重载c风格
bool find(const char *str)
{ return find(str,str+strlen(str));
} private: //清空
void clear_node(node_type cur)
{
for(int i=; i<Size; i++)
{
if(cur.child[i]==)continue; //不存在
clear_node(*cur.child[i]);
delete cur.childe[i];
cur.child[i]=;
if(--cur.node==) break; //没有节点了 } } //根
node_type root;
//字符转索引,类似hash
Index index; }; class IndexClass
{
public:
int operator[](const char key)
{
return key%; //一个映射 } }; int main()
{
trie<,IndexClass> t;
scanf("%s",str2) ; while(scanf("%s",str1))
{
if(str1[]=='E')
{ break;
}
scanf("%s",str2);
t.insert(str2);
}
scanf("%s",str2); getchar(); while(gets(st))
{ if(st[]=='E')
{ break;
}
int len=strlen(st);
int bg=;
for(int i=; i<len; i++)
{
if(st[i]>='a'&&st[i]<='z')
{ continue;
}
if(!t.find(st+bg,st+i))
{
for(int j=bg; j<i; j++)
printf("%c",st[j]); };
if(st[i]) printf("%c",st[i]);
bg=i+; } puts(""); } return ; }
WA的:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
using namespace std;
char str1[];
char str2[];
char st[]; template<int Size>
struct trie_node
{ bool terminable; //表示节点为字符串的结尾
int node; //子节点的个数
char str[];
trie_node *child[Size]; //儿子节点
trie_node():terminable(false), node()
{
memset(child,,sizeof(child)); //初始化节点
} }; template<int Size,typename Index>
class trie
{
public:
//定义类名
typedef trie_node<Size> node_type;
typedef trie_node<Size> *link_type; //构造函数
trie(Index i=Index()):index(i) { } //清空函数,用于析构
void clear()
{
clear_node(root);
for(int i=; i<Size; i++)
root.child[i]=;
}
//插入
template<typename Iterator>
void insert(Iterator begin,Iterator end)
{
link_type cur= &root;//当前插入结点为根
while(begin!=end)
{
if(cur->child[index[*begin]]) //插入过
{
cur=cur->child[index[*begin]];
++(cur->node); }
else
{
cur->child[index[*begin]]=new node_type;
++(cur->child[index[*begin]]->node);
cur=cur->child[index[*begin]]; } begin++; //迭代器往前走!
}
cur->terminable=true;
int len=strlen(str1);
for(int i=; i<len; i++)
cur->str[i]=str1[i]; } //重载c风格插入
void insert(const char * str)
{
insert(str,str+strlen(str));
} //查找
template <typename Iterator>
bool find(Iterator begin,Iterator end)
{
link_type cur=&root;
while(begin!=end)
{ if(!cur->child[index[*begin]]) //没有节点啊!!!
return false;
cur=cur->child[index[*begin]]; begin++; }
// printf("%s sb",cur->str);
if(cur->terminable)
{
printf("%s",cur->str);
return true; }
return false; //是否为字符串
} //重载c风格
bool find(const char *str)
{ return find(str,str+strlen(str));
} private: //清空
void clear_node(node_type cur)
{
for(int i=; i<Size; i++)
{
if(cur.child[i]==)continue; //不存在
clear_node(*cur.child[i]);
delete cur.childe[i];
cur.child[i]=;
if(--cur.node==) break; //没有节点了 } } //根
node_type root;
//字符转索引,类似hash
Index index; }; class IndexClass
{
public:
int operator[](const char key)
{
return key%; //一个映射 } }; int main()
{
trie<,IndexClass> t;
scanf("%s",str2) ; while(scanf("%s",str1))
{
if(str1[]=='E')
{ break;
}
scanf("%s",str2);
t.insert(str2);
}
scanf("%s",str2); getchar(); while(gets(st))
{ if(st[]=='E')
{ break;
}
int len=strlen(st);
int bg=;
for(int i=; i<len; i++)
{
if(st[i]>='a'&&st[i]<='z')
{ continue;
}
if(!t.find(st+bg,st+i))
{
for(int j=bg; j<i; j++)
printf("%c",st[j]); };
if(st[i]) printf("%c",st[i]);
bg=i+; } puts(""); } return ; }

(差别就在字符串copy 上没有拷贝上'\0'……,也就是st[len])

HDU1247
题目相对理解上会有点偏差,不是当且仅当两个,是两个,举个例子
a
abc
b
bc
c
输出的是:abc,bc(注意abc也是,不要因为abc=a+b+c,而忽略,只要可以满足s=s1+s2即可,即abc=a+bc,bc=b+c)
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
template<int Size>
struct trie_node{ bool terminable; //表示节点为字符串的结尾
int node; //子节点的个数 trie_node *child[Size]; //儿子节点
trie_node():terminable(false), node(){
memset(child,,sizeof(child)); //初始化节点
} }; template<int Size,typename Index>
class trie{
public:
//定义类名
typedef trie_node<Size> node_type;
typedef trie_node<Size> *link_type; //构造函数
trie(Index i=Index()):index(i){ } //清空函数,用于析构
void clear(){
clear_node(root);
for(int i=;i<Size;i++)
root.child[i]=;
}
//插入
template<typename Iterator>
void insert(Iterator begin,Iterator end){ link_type cur= &root;//当前插入结点为根
while(begin!=end){
if(cur->child[index[*begin]]){//插入过
cur=cur->child[index[*begin]];
++(cur->node); }else{
cur->child[index[*begin]]=new node_type;
++(cur->child[index[*begin]]->node);
cur=cur->child[index[*begin]]; } // cout<<*begin;
begin++; //迭代器往前走!
}
cur->terminable=true; // cout<<cur->id<<endl; } //重载c风格插入
void insert(const char * str){
insert(str,str+strlen(str));
} //查找
template <typename Iterator>
bool find(Iterator begin,Iterator end){
link_type cur=&root; while(begin!=end){ if(!cur->child[index[*begin]])return false; //我在这里re了无数次…忧桑…… cur=cur->child[index[*begin]]; begin++; }
// cout<<*begin<<" "<<*end<<"sb" <<endl;
return cur->terminable; } //重载c风格
bool find(const char *str){ return find(str,str+strlen(str));
} private: //清空
void clear_node(node_type cur){
for(int i=;i<Size;i++){
if(cur.child[i]==)continue; //不存在
clear_node(*cur.child[i]);
delete cur.childe[i];
cur.child[i]=;
if(--cur.node==) break; //没有节点了 } } //根
node_type root;
//字符转索引,类似hash
Index index; }; class IndexClass{
public:
int operator[](const char key){
return key%; //一个映射 } };
char str[][]; int main(){
trie<,IndexClass> t;
int i=; while(scanf("%s",str[i])!=EOF){
// cout<<str[i];
t.insert(str[i]);
i++;
} for(int j=;j<i;j++){ int len=strlen(str[j]);
for(int p=;p<=len-;p++){ if(t.find(str[j],str[j]+p)){ if(t.find(str[j]+p)){ printf("%s\n",str[j]);
break;
} } } } return ; }

尽管我上面这个做法已经OK了,但是这是参考了别人,下面是我完全按自己想法写的,程序员最高兴的莫过于可以将自己的想法实现。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
template<int Size>
struct trie_node{ bool terminable; //表示节点为字符串的结尾
int node; //子节点的个数 trie_node *child[Size]; //儿子节点
trie_node():terminable(false), node(){
memset(child,,sizeof(child)); //初始化节点
} }; template<int Size,typename Index>
class trie{
public:
//定义类名
typedef trie_node<Size> node_type;
typedef trie_node<Size> *link_type; //构造函数
trie(Index i=Index()):index(i){ } //清空函数,用于析构
void clear(){
clear_node(root);
for(int i=;i<Size;i++)
root.child[i]=;
}
//插入
template<typename Iterator>
void insert(Iterator begin,Iterator end){ link_type cur= &root;//当前插入结点为根
while(begin!=end){
if(cur->child[index[*begin]]){//插入过
cur=cur->child[index[*begin]];
++(cur->node); }else{
cur->child[index[*begin]]=new node_type;
++(cur->child[index[*begin]]->node);
cur=cur->child[index[*begin]]; } // cout<<*begin;
begin++; //迭代器往前走!
}
cur->terminable=true; // cout<<cur->id<<endl; } //重载c风格插入
void insert(const char * str){
insert(str,str+strlen(str));
} //查找
template <typename Iterator>
bool find(Iterator begin,Iterator end,int i){
link_type cur=&root; while(begin!=end){ if(cur->terminable){
if(i>) return false;
if( find(begin,end,i+))return true;
} if(!cur->child[index[*begin]]) return false;
cur=cur->child[index[*begin]]; begin++; }
if(!cur->terminable){
return false;
}
return i==; } //重载c风格
bool find(const char *str,int i){ return find(str,str+strlen(str),i);
} private: //清空
void clear_node(node_type cur){
for(int i=;i<Size;i++){
if(cur.child[i]==)continue; //不存在
clear_node(*cur.child[i]);
delete cur.child[i];
cur.child[i]=;
if(--cur.node==) break; //没有节点了 } } //根
node_type root;
//字符转索引,类似hash
Index index; }; class IndexClass{
public:
int operator[](const char key){
return key%; //一个映射 } };
char str[][]; int main(){
trie<,IndexClass> t;
int i=;
//freopen("in.txt","r",stdin);
while(scanf("%s",str[i])!=EOF){
// cout<<str[i];
t.insert(str[i]);
i++;
} for(int j=;j<i;j++){ if(t.find(str[j],)){ //类似与dfss printf("%s\n",str[j]);
} } return ; }

HDU1857,逆向思维的trie,可以参考我之前写过的,点这里

http://acm.hdu.edu.cn/showproblem.php?pid=1857

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
template<int Size>
struct trie_node{ bool terminable; //表示节点为字符串的结尾
int node; //子节点的个数
int id;
trie_node *child[Size]; //儿子节点
trie_node():terminable(false), node(){
memset(child,,sizeof(child)); //初始化节点
} };
int RR[],CC[];
template<int Size,typename Index>
class trie{
public:
//定义类名
typedef trie_node<Size> node_type;
typedef trie_node<Size> *link_type; //构造函数
trie(Index i=Index()):index(i){ } //清空函数,用于析构
void clear(){
clear_node(root);
for(int i=;i<Size;i++)
root.child[i]=;
}
//插入
template<typename Iterator>
void insert(Iterator begin,Iterator end,int i){ link_type cur= &root;//当前插入结点为根
while(begin!=end){
if(cur->child[index[*begin]]){//插入过
cur=cur->child[index[*begin]];
++(cur->node); }else{
cur->child[index[*begin]]=new node_type;
++(cur->child[index[*begin]]->node);
cur=cur->child[index[*begin]]; } begin++; //迭代器往前走!
}
cur->terminable=true;
cur->id=i; } //重载c风格插入
void insert(const char * str,int i){
insert(str,str+strlen(str), i);
} //查找
template <typename Iterator>
void find(Iterator begin,Iterator end,int r,int c){
link_type cur=&root;
while(begin!=end){ if(cur->terminable){ if(RR[cur->id]==){ RR[cur->id]=r;
CC[cur->id]=c;
}
} if(!cur->child[index[*begin]]) //没有节点啊!!!
return ; cur=cur->child[index[*begin]]; begin++; }
if( cur->terminable) {//是否为字符串 if(RR[cur->id]==){ RR[cur->id]=r;
CC[cur->id]=c;
}
} } //重载c风格
void find(const char *str,int r,int c){ find(str,str+strlen(str),r,c);
} private: //清空
void clear_node(node_type cur){
for(int i=;i<Size;i++){
if(cur.child[i]==)continue; //不存在
clear_node(*cur.child[i]);
delete cur.childe[i];
cur.child[i]=;
if(--cur.node==) break; //没有节点了 } } //根
node_type root;
//字符转索引,类似hash
Index index; }; class IndexClass{
public:
int operator[](const char key){
return key%; //一个映射 } };
char cc[][];
char s[];
int mini(int a,int b){
return a>b?b:a;
}
int main(){
trie<,IndexClass> t;
int R,C,i,j,l,ed;
scanf("%d%d",&R,&C);
getchar(); //读掉回车
for( i=;i<R;i++)
{ gets(cc[i]);
} int N=;
while(gets(s)&&s[]!='-'){
if(s[]){
t.insert(s,N); //用每一个要查找的单词构树
N++;
} } for(i=;i<R;i++)
for( j=;j<C;j++){
//向下
memset(s,,sizeof(s));
if(i+<R) ed=;
else ed=R-i;
for(l=;l<ed;l++){
s[l]=cc[i+l][j]; } t.find(s,i+,j+);
//向右
memset(s,,sizeof(s));
if(j+<C) ed=;
else ed=C-j;
for( l=;l<ed;l++){
s[l]=cc[i][j+l]; } t.find(s,i+,j+); //右下
memset(s,,sizeof(s));
if(i+<R&&j+<C) ed=;
else ed=mini(C-j,R-i);
for( l=;l<ed;l++){
s[l]=cc[i+l][j+l]; } t.find(s,i+,j+); } for( i=;i<N;i++){ if(RR[i]!=||CC[i]!=)
printf("%d %d\n",RR[i]-,CC[i]-);
else puts("-1 -1");
} return ; }

Trie树入门及训练的更多相关文章

  1. Trie树入门

    Trie树入门 貌似很多人会认为\(Trie\)是字符串类型,但是这是数据结构!!!. 详情见度娘 下面开始进入正题. PS:本文章所有代码未经编译,有错误还请大家指出. 引入 先来看一个问题 ​ 给 ...

  2. HDOJ1251-统计难题(trie树入门)

    统计难题 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others) Total Subm ...

  3. hdu 1251 统计难题(trie树入门)

    统计难题 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others)Total Submi ...

  4. hdu1251(Trie树)

    传送门:统计难题 分析:Trie树入门题,随便写写练下手感,统计每个节点被多少单词经过就可以了. #include <iostream> #include <cstdio> # ...

  5. HDU1251 统计难题 【trie树】

    统计难题 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others) Total Subm ...

  6. 字典(trie)树--从入门到入土

    今天再来认识一个强大的数据结构. 字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词 ...

  7. 基于trie树的具有联想功能的文本编辑器

    之前的软件设计与开发实践课程中,自己构思的大作业题目.做的具有核心功能,但是还欠缺边边角角的小功能和持久化数据结构,先放出来,有机会一点点改.github:https://github.com/chu ...

  8. trie树--详解

    文章作者:yx_th000 文章来源:Cherish_yimi (http://www.cnblogs.com/cherish_yimi/) 转载请注明,谢谢合作.关键词:trie trie树 数据结 ...

  9. 转:trie树--详解

    前几天学习了并查集和trie树,这里总结一下trie. 本文讨论一棵最简单的trie树,基于英文26个字母组成的字符串,讨论插入字符串.判断前缀是否存在.查找字符串等基本操作:至于trie树的删除单个 ...

随机推荐

  1. UVa 1252 - Twenty Questions(记忆化搜索,状态压缩dp)

    本文出自   http://blog.csdn.net/shuangde800 题目链接:点击打开链接 题目大意 有n个长度为m的二进制串,每个都是不同的. 为了把所有字符串区分开,你可以询问,每次可 ...

  2. psp开发------汉化插件

    近期略微研究了下psp汉化,写了个汉化插件,在这记录下.聊以慰藉. 传统的汉化流程找码表,字库,破解什么这里不多讲,网上有教程.以下说下一种另类汉化方法.特别对于难以破解字库的游戏,当然这样的方法也有 ...

  3. 【智能家居篇】wifi在智能家居中的应用

    转载请注明出处:http://blog.csdn.net/Righthek 谢谢! 在设计智能家居系统方案时,一个很关键的point就是组网方式.组网方式关系到整个智能家居系统的稳定性.可扩展性.实时 ...

  4. 细说linux挂载——mount,及其他……

    http://forum.ubuntu.org.cn/viewtopic.php?t=257333

  5. Cookie和Session(session过程和设置进程外session)

    cookie 和  session 的区别 cookie 是保存在客户端上的一种机制   而session 是保存在服务端的一种机制 cookie的理解: 打个简单的比方,一个人生病了去A医院看病,回 ...

  6. Ubuntu14.04 Kylin下 GO语言环境搭建

    sudo apt-get install golang gccgo安装 gcc -v 查看 --enable-languages=c,c++,objc,obj-c++,java,fortran,ada ...

  7. linux - 输入输出重定向 及 管道

    > 正确结果重定向 2> 错误结果重定向 &> 正确和错误全部重定向 >> 追加,其它同> 标准输出实际上就是显示器,比如我们使用cat命令打开一个文件,文 ...

  8. RedHat7搭建yum源服务器

    1.新建目录 # mkdir -p /content/rhel7/x86_64/{isos,dvd}/ 2.上传RedHat安装光盘镜像,上传后的路径为 /content/rhel7/x86_64/i ...

  9. MSP430常见问题之电源类

    Q1:msp430(我用的4619)的VCC,DVCC,VSS,DVSS怎么接啊?模拟的和数字的一样吗?A1:CC 就是正,SS 就是负,A是模拟电,D 是数字电,A的都接在一起,D 的都接在一起,地 ...

  10. Git CMD - checkout: Switch branches or restore working tree files

    命令格式 git checkout [-q] [-f] [-m] [<branch>] git checkout [-q] [-f] [-m] --detach [<branch&g ...