- /****************************字典树Trie模板***********************************/
- #define MAX 26
- struct Trie
- {
- Trie *next[MAX]; //next表示每层有多少种类的数
- int v; //每个字典树有多少个前缀相同的个数
- void init()
- {
- for(int i=0;i<MAX;i++)
- next[i]=NULL;
- v=1;
- }
- };
- Trie root;
- void Trie_insert(Trie *root,char *s)
- {
- int n=strlen(s);
- Trie *p=root,*q;
- p->v++;
- for(int i=0;i<n;i++)
- {
- int id=s[i]-'a';
- if(p->next[id]==NULL)
- {
- q=(Trie*)malloc(sizeof(Trie));
- q->init();
- p->next[id]=q;
- p=q;
- }
- else
- {
- p->next[id]->v++;
- p=p->next[id];
- }
- }
- }
- int Trie_search(Trie *root,char *s)
- {
- int n=strlen(s);
- Trie *p=root;
- for(int i=0;i<n;i++)
- {
- int id=s[i]-'a';
- if(p->next[id]==NULL)
- return 0;//没找到该前缀
- else
- p=p->next[id];
- }
- return p->v;
- }
- void Trie_delete(Trie *root)
- {
- if(root==NULL)
- return ;
- else
- {
- for(int i=0;i<MAX;i++)
- Trie_delete(root->next[i]);
- }
- free(root);
- }
- /****************************字典树Trie模板***********************************/
int trie[1000010][26]; //数组形式定义字典树,值存储的是下一个字符的位置
int num[1000010]={0}; //附加值,以某一字符串为前缀的单词的数量
int pos = 1;
void Insert(char word[]) //在字典树中插入某个单词
{
int i;
int c = 0;
for(i=0;word[i];i++){
int n = word[i]-'a';
if(trie[c][n]==0) //如果对应字符还没有值
trie[c][n] = pos++;
c = trie[c][n];
num[c]++;
}
}
int Find(char word[]) //返回以某个字符串为前缀的单词的数量
{
int i;
int c = 0;
for(i=0;word[i];i++){
int n = word[i]-'a';
if(trie[c][n]==0)
return 0;
c = trie[c][n];
}
return num[c];
}
int num[1000010]={0}; //附加值,以某一字符串为前缀的单词的数量
int pos = 1;
void Insert(char word[]) //在字典树中插入某个单词
{
int i;
int c = 0;
for(i=0;word[i];i++){
int n = word[i]-'a';
if(trie[c][n]==0) //如果对应字符还没有值
trie[c][n] = pos++;
c = trie[c][n];
num[c]++;
}
}
int Find(char word[]) //返回以某个字符串为前缀的单词的数量
{
int i;
int c = 0;
for(i=0;word[i];i++){
int n = word[i]-'a';
if(trie[c][n]==0)
return 0;
c = trie[c][n];
}
return num[c];
}
开始先放上字典树模板(两组代码);
Trie树的实现,可以用数组,也可以用指针动态分配。
Trie树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
Trie树的基本性质可以归纳为:
- 根节点不包含字符,除根节点意外每个节点只包含一个字符。
- 从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。
- 每个节点的所有子节点包含的字符串不相同。
Trie树有一些特性:
- 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
- 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
- 每个节点的所有子节点包含的字符都不相同。
- 如果字符的种数为n,则每个结点的出度为n,这也是空间换时间的体现,浪费了很多的空间。
- 插入查找的复杂度为O(n),n为字符串长度。
基本思想(以字母树为例):
-
插入过程
对于一个单词,从根开始,沿着单词的各个字母所对应的树中的节点分支向下走,直到单词遍历完,将最后的节点标记为红色,表示该单词已插入Trie树。
-
查询过程
同样的,从根开始按照单词的字母顺序向下遍历trie树,一旦发现某个节点标记不存在或者单词遍历完成而最后的节点未标记为红色,则表示该单词不存在,若最后的节点标记为红色,表示该单词存在。
在Trie树中主要有3个操作,插入、查找和删除。一般情况下Trie树中很少存在删除单独某个结点的情况,因此只考虑删除整棵树。
-
插入
假设存在字符串str,Trie树的根结点为root。i=0,p=root。
- 取str[i],判断p->next[str[i]-97]是否为空,若为空,则建立结点temp,并将p->next[str[i]-97]指向temp,然后p指向temp;
若不为空,则p=p->next[str[i]-97]; - i++,继续取str[i],循环1)中的操作,直到遇到结束符’\0’,此时将当前结点p中的 exist置为true。
- 取str[i],判断p->next[str[i]-97]是否为空,若为空,则建立结点temp,并将p->next[str[i]-97]指向temp,然后p指向temp;
-
查找
假设要查找的字符串为str,Trie树的根结点为root,i=0,p=root
- 取str[i],判断判断p->next[str[i]-97]是否为空,若为空,则返回false;若不为空,则p=p->next[str[i]-97],继续取字符。
- 重复1)中的操作直到遇到结束符’\0’,若当前结点p不为空并且 exist 为true,则返回true,否则返回false。
-
删除(二选其一)
- 删除可以以递归的形式进行删除。
- 先搜索后删除
- 字典树在判断一个单词是否属于字典时很有优势,但是字典树在判断一个文本包含多少个字典中的单词时就显得不足。字典树基本上都是模板题。