字典树 Trie

字典树 目录

原理

字典树又称前缀树,当我们要存储多个字符串时,若每段字符串单独存储,则查找以及空间效率都很低。
有一些字符串是另一些的前缀,或者两个字符串的前缀有重合,利用这一性质,我们建一个字典树,又叫前缀树,前缀相同的字符串前缀相同部分都只会被存储一次

例子

字典树 Trie
有字符串 a,ab ,acd,bc;

  1. 对于每个插入的字符串,首先从根节点出发,查找是否有匹配的子节点 如插入 "ab"时,首先在 root节点查找是否有 值为’a’的子节点,若没有,则直接插入。
  2. 再对该节点进行如第一步操作,继续查找是否有下一字符的节点。
  3. 若到达字符串尾部,则结束,标记该点。

结论

1.从根节点到任意被标记的节点,都是一个字符串。
2.有相同前缀的两个字符串,它们在树中一部分重复。

具体实现

虽然是树,但是一般不用指针实现,因为指针操作太繁琐
这里用的是数组实现,而每个节点存的就是它不是子节点的指针,而是下标 。
下面是节点结构:

struct tree{
	int vis[26];//存子节点下标
	int end;//判断是否是字符串
}ac[10000005];
  • vis数组存储子节点下标,这个字典树处理的是英语字母上的字符串,字符集有26个元素,因此最多有26个子节点。
  • end用来判断从根节点到该节点是否构成一个字符串。

构造:

int cnt;//trie树中结点个数
void build(int n){
	int i,j,k,l,now;
	for(i=0;i<n;i++){
		scanf("%s",s);
		l=strlen(s),now=0;//默认根节点下标为0
		for(j=0;j<l;j++){
			if(ac[now].vis[s[j]-'a']==0)//不存在
			ac[now].vis[s[j]-'a']=++cnt;//插入结点
			now=ac[now].vis[s[j]-'a'];//更新当前结点
		}
		ac[now].end+=1;//数目加一
	}
}
  • cnt存储的是结点个数
  • vis子节点不存在默认初始化为0
  • now存储当前结点

到了这里 一个trie树就建成了,至于具体应用?等我的ac自动机吧。

上一篇:可持久化trie


下一篇:Trie树/字典树