Trie树
Trie树,又称字典树,单词查找树,顾名思义,字典树与字典很相似,是一种经常用于统计,排序,保存大量字符的数据结构。Trie树利用字符串的公共前缀来节约存储空间,因此其效率很高,所以在在字符串查找、前缀匹配等中应用很广泛。不过其高效率是以花费大量空间为代价的。
Trie树的构造(以26小写字母为例)
Trie树数据结构定义
#define MAX 10
struct Trie{
Trie *next[MAX]; //分支数
int v;//以当前字符串为前缀的个数
};
其中next
为存放着节点指向孩子节点的指针。v
可以根据自己的目的变化,这里可以是以 到当前节点的为前缀的字符串的个数。
Trie树的操作
插入操作
插入操作可以理解为建树的过程,可以这样理解:
假设Trie的根节点是root,当前字符串为str,当前节点指针为p,初始为root
遍历str:
若p->next[str[i]-'a']为空,则说明之前没有此前缀,需要新建节点q, 更新p->next[], 同时更新p
若不为空, 则说明之前已经有了该前缀,只需要更新p以及 计数
具体代码如下:
void createTrie(char *str)
{
int len=strlen(str);
Trie *p=root,*q;
for(int i=0; i<len;i++)
{
int id= str[i]-'a';
if(!p->next[id])
{
q=(Trie*) malloc(sizeof(Trie));
q->v=1;
for(int j=0; j<MAX; j++)
{//更新节点的next指针
q->next[j]=NULL;
}
p->next[id]=q;
p=p->next[id];
}
else
{
p->next[id]->v++;//更新计数
p=p->next[id];
}
}
}
查找操作
(1) 每次从根结点开始一次搜索;
(2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;
(3) 在相应的子树上,取得要查找关键词的第二个字母,进一步选择对应的子树进行检索。
(4) 迭代过程……
(5) 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。 否则查找失败.
具体查找代码如下:
int findTrie(char *str)
{//返回以当前前缀的个数,复杂度O(len)
int len=strlen(str);
Trie * p= root;
for(int i=0; i<len; i++)
{
int id=str[i]-'a';
p=p->next[id];
if(!p) return 0;
}
return p->v;
}
删除操作
本来删除可以不用我们完成的,不过在有些情况下, 需要动态的不断的建立树,就需要我们手动释放内存了,对Trie树的删除一般指删除整棵树。
直接递归 由下到上释放对象即可.
void del(Trie *T)
{
if (!T) return;
for(int i=0; i<MAX; i++)
{
if(T->next[i]) del(T->next[i]);
}
free(T);
}
字典树的基本介绍就是这些了,后面做几道ACM题巩固巩固。