前面我已经写了两篇关于字典树的博客,主要说的是动态建立字典树,详情请看:
http://blog.csdn.net/monkey0le/article/details/8095918
http://blog.csdn.net/monkey0le/article/details/8096105
由于动态的字典树需要动态申请内存,而且每一组测试数据用完后都需要释放内存,很容易会造成泄漏和非法访问内存等一系列问题,今天看了lrj的《算法竞赛入门经典——训练指南》,里面说的字典树是静态的,感觉和静态链表有异曲同工之妙,放上来和大家分享一下:
首先需要一个二维数组ch[i][j]保存结点i的那个编号为j的子结点。感觉好像有点抽象,下面画个图给大家就明白了。
假设给出一个字符串集合{a,to,tea,ted,i,in},下面的就是构建的字典树:
如上图,红色的数字代表的就是i,j对应的就是i那个结点的字符减去‘a’字符得到的编号,三角形就代表一个单词的结束。ch[i][j]代表的就是该结点对应的孩子结点的位置。
lrj的代码只给出了插入的,很容易就可以写出查询的代码:
struct Trie {
int ch[maxnode][sigma_size];
int val[maxnode]; //附加信息
int sz; //节点总数
Trie () {sz = 1; memset (ch[0], 0, sizeof (ch[0])); } //初始化
int idx (char c) { return c - 'a';}
void insert (char *s, int v)
{//插入字符串s,附加信息为v,v不为0
int u = 0,n = strlen (s);
for (int i = 0; i < n; i++)
{
int c = idx (s[i]);
if (!ch[u][c])
{//节点不存在
memset (ch[sz], 0, sizeof (ch[sz]));
val[sz] = 0; //中间节点附加信息为0
ch[u][c] = sz ++; //新建节点
}
u = ch[u][c]; //往下走
}
val[u] = v; //字符串的最后一个字符的附加信息为v
}
int Search (char *s) //查找字符串s,返回附加信息
{
int u = 0, n = strlen (s);
for (int i = 0; i < n; i++)
{
int c = idx (s[i]);
if (!ch[u][c])
{//节点不存在
return 0;
}
u = ch[u][c];
}
return val[u];
}
};