字典树及应用
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Trie树(字典树)
Trie树就是字符树,其核心思想就是空间换时间。
举个简单的例子。
给你100000个长度不超过10的单词。对于每一个单词,我们要判断他出没出现过,如果出现了,第一次出现第几个位置。
这题当然可以用hash来,但是我要介绍的是trie树。在某些方面它的用途更大。比如说对于某一个单词,我要询问它的前缀是否出现过。这样hash就不好搞了,而用trie还是很简单。
现在回到例子中,如果我们用最傻的方法,对于每一个单词,我们都要去查找它前面的单词中是否有它。那么这个算法的复杂度就是O(n^2)。显然对于100000的范围难以接受。现在我们换个思路想。假设我要查询的单词是abcd,那么在他前面的单词中,以b,c,d,f之类开头的我显然不必考虑。而只要找以a开头的中是否存在abcd就可以了。同样的,在以a开头中的单词中,我们只要考虑以b作为第二个字母的……这样一个树的模型就渐渐清晰了……
假设有b,abc,abd,bcd,abcd,efg,hii这6个单词,我们构建的树就是这样的。
对于每一个节点,从根遍历到他的过程就是一个单词,如果这个节点被标记为红色,就表示这个单词存在,否则不存在。
那么,对于一个单词,我只要顺着他从跟走到对应的节点,再看这个节点是否被标记为红色就可以知道它是否出现过了。把这个节点标记为红色,就相当于插入了这个单词。
这样一来我们询问和插入可以一起完成,所用时间仅仅为单词长度,在这一个样例,便是10。
我们可以看到,trie树每一层的节点数是26^i级别的。所以为了节省空间。我们用动态链表,或者用数组来模拟动态。空间的花费,不会超过单词数×单词长度。
由字母a~z所组成的字符串的一个集合中,各个字符的长度之和为n。设计一个O(n)时间的算法,将这个集合中所有字符串依字典进行排序。注意,这里可能存在非常长的字符串。
#include
#include
typedef struct tire
{
struct tire *next[26];
char date;
int cnt;
}*_tire;
void init_tire(_tire root, char *string)
{
_tire s;
s=root;
while(*string!='\0')
{
if(s->next[*string - 'a']==NULL)
{
s->next[*string - 'a'] = (_tire)malloc(sizeof(struct tire));
(s->next[*string - 'a'])->date = *string;
s = s->next[*string - 'a']; for(int i=0;i<26;i++)
{
s->next[i] = NULL;
}
}
else
{
s = s->next[*string - 'a']; }
string++;
}
s->cnt=1;
}
void print(_tire root, char *s, int i) {
int j;
s[i] = root->date;
if(root->cnt==1)
{
s[i+1] = 0;
puts(s);
}
for(j=0;j<26;j++)
{
if(root->next[j]!=NULL)
{
print(root->next[j],s,i+1);
}
}
}
int main()
{
_tire root;
int m,i;
char s[265];
root = (_tire)malloc(sizeof(struct tire)); puts("输入字符串个数:");
for(i=0;i<26;i++)
{
root->next[i]=NULL;
}
scanf("%d",&m);
getchar();
while(m--)
{
gets(s);
init_tire(root,s);
}
puts("\n依字典排序后:");
for(i=0;i<26;i++)
{
if(root->next[i] != NULL)
{
print(root->next[i],s,0);
}
}
return 0;
}
Trie
赞助商
Trie,又叫单词树、字典树。故名思义,单词树是一棵保存关键字的树。对于英语单词而言,单词树是一棵26 叉树,即每一个根结点有26 个孩子。(文/dngc)
举例:要保存单词{ add, am, the, think, good }
则画出来的单词树的图为:
附件:
R 代表单词树的根。构造了这样一棵树后,我们很容易查找某个单词是否在单词树中,效率非常高。只是单词树消耗的内存非常大。很容易得到单词树的构造算法:
HDU 1251 统计难题( 单词树的基本应用)
代码:
1#include
2#include
3#include
4
5int const N= 1000000;
6struct Trie{
7int id; // 标记每一个单词
8int cnt; // 标记单词前缀的数量
9int next[26]; // 26 个孩子结点