[模板]-AC自动机
2017-09-08 22:27
393 查看
问题描述:
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
代码:
解决方法:小心使用未被初始化的变量。
Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串)
根节点(Trie的入口,没有实际含义)不包含字符,除根节点外每一个节点都只包含一个字符
AC自动机优化后可称Trie图
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
代码:
char t[1000010];//模式串 char s[1000010];//主串 struct Trie//字典树中的一个结点 { Trie* fail;//失配指针 Trie* next[26];//该结点的儿子,最多有26个 int sum;//以该结点所代表的字母结尾的单词数 // Trie()//初始化 // { // fail = NULL; // memset(next,NULL,sizeof(next)); // sum = 0; // } }; Trie* root; void init(Trie* node)//初始化函数 { node -> fail = NULL; for(int i = 0; i <= 25; ++i) node -> next[i] = NULL; node -> sum =0; } void BuildTree(char t[])//建树 { Trie* p = root;//从根结点开始 Trie* q; int len = strlen(t);//模式串t的长度 for(int i = 0; i <= len - 1; ++i) { int index = t[i] - 'a';//索引,a对应0,b对应1,以此类推 if(p -> next[index] == NULL)//如果没有边 { q = (Trie*)malloc(sizeof(Trie)); init(q); p -> next[index] = q;//就新建一个结点,产生一条边,新结点代表该字母 } p = p -> next[index];//继续向下 } p->sum++;//单词最后一个结点的sum加1 } queue<Trie*> q;//队列,用于求失配指针 void GetFail(Trie* root)//广度优先搜索求失配指针 { q.push(root);//首先将root加入队列 while(!q.empty()) { Trie *t = q.front(),*p;//访问队首 q.pop();//弹出队首 for(int i = 0; i <= 25; ++ 4000 i) { if(t -> next[i] != NULL)//如果t的该儿子结点存在 { if(t == root)//如果t -> next[i]是第一层中的结点,就将其失配指针指向root t ->next[i] ->fail = root; else { p = t -> fail;//将父节点t的失配指针赋给扫描指针p while(p != NULL)//扫描指针不为空(根结点的失配指针)时循环 { if(p -> next[i] != NULL)//如果扫描指针p的儿子结点p -> next[i]不为空,即t -> next[i]与p -> next[i]相同 { t -> next[i] -> fail = p -> next[i];//将t的儿子结点t -> next[i]的失配指针指向p -> next[i] break;//跳出循环 } p = p -> fail;//否则继续回溯 } if(p == NULL)//如果p最终为root结点的fail指针(即NULL) t -> next[i] -> fail = root;//将t -> next[i]的失配指针指向root } q.push(t -> next[i]); } } } } int Aho_Corasick_Automaton(Trie* root)//匹配 { Trie* p = root;//p为模式串指针 int len = strlen(s);//主串的长度 int cnt = 0;//计数 for(int i = 0; i <= len - 1; ++i)//i为主串指针 { int index = s[i] - 'a';//索引 while(p -> next[index] == NULL && p != root)//当p -> next[index]为空或p不指向root时进行循环 p = p -> fail;//失配指针回溯 p = p -> next[index];//循环结束后将p指向p -> next[index] if(p == NULL)//如果p为空,说明与s[i]匹配的字符不存在 p = root; Trie* t = p;//指向p -> next[index]后,沿其失败指针回溯,判断其它结点是否与s[i]匹配 while(t != root)//如果t不指向root,否则不会进行循环 { if(t->sum >= 0)//判断该结点是否被访问过 { cnt += t -> sum;//累加 t -> sum = -1;//标记为已访问过 } else//结点被访问过 break;//结束循环 t = t -> fail;//回溯失配指针,继续寻找下一个满足条件的结点 } } return cnt; } int main() { int n;//模式串个数 cin >> n; root = (Trie*)malloc(sizeof(Trie));//根 init(root); for(int i = 1; i <= n; ++i) { scanf("\n%s",t);//输入模式串 BuildTree(t);//建立字典树Trie } scanf("%s",s);//输入主串 GetFail(root);//获得失配指针 printf("%d\n",Aho_Corasick_Automaton(root));//打印答案 }
解决方法:小心使用未被初始化的变量。
Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串)
根节点(Trie的入口,没有实际含义)不包含字符,除根节点外每一个节点都只包含一个字符
AC自动机优化后可称Trie图
相关文章推荐
- AC自动机模板
- hdu 2222 Keywords Search(AC自动机模板)
- HDU2222 AC自动机模板
- ac自动机模板(hdu2222)
- hdu 2222 Keywords_ac自动机模板
- ac自动机 模板
- 洛谷P3796 - 【模板】AC自动机(加强版)
- AC自动机模板(【洛谷3808】)
- AC自动机模板(hdu2222)
- 数据结构--AC自动机--模板
- ac自动机模板
- [洛谷3796]【模板】AC自动机(加强版)
- AC自动机以及KMP模板
- P3796 【模板】AC自动机(加强版)
- AC自动机模板
- hdu 2222(AC自动机模板)
- HDOJ2222Keywords Search【AC自动机模板题】
- AC自动机 [模板]
- HDU2222【AC自动机(基础·模板)】
- AC自动机(1)--hdu2222(基本模板)