Aho-Corasick算法—Trie图(AC自动机)

功能:解决多模式串匹配问题

算法步骤:建立Trie树点击打开链接,以此为基础添加失败指针,以母串作为DFA的输入,在DFA 上行走,走到终止节点,就意味着匹配了相应的模式串。


ps:根据深度一一求出每一个节点的失败指针;第二层要特殊处理,将这层中的节点的失败指针直接指向父节点(也就是根节点);


代码:

//数据结构 
const int kind = 26;
 
struct node{  
    node *fail;       //失败指针
    node *next[kind]; //Tire每个节点的个子节点(最多个字母)
    int count;        //是否为该单词的最后一个节点
    node(){           //构造函数初始化
        fail=NULL; 
        count=0; 
        memset(next,NULL,sizeof(next)); 
    } 
}*q[500001];          //队列,方便用于bfs构造失败指针

char keyword[51];     //输入的单词
char str[1000001];    //模式串
int head,tail;        //队列的头尾指针


//Trie树 
void insert(char *str,node *root)
{ 
    node *p=root; 
    int i=0,index;  
    while(str[i])
	{ 
        index=str[i]-'a'; 
        if(p->next[index]==NULL) p->next[index]=new node();  
        p=p->next[index];
        i++;
    } 
    p->count++;     //在单词的最后一个节点count+1,代表一个单词
}


/*构造失败指针: 设这个节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,
他的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字母也为C的儿子。
如果一直走到了root都没找到,那就把失败指针指向root。*/
 void build_ac_automation(node *root){
    int i;
    root->fail=NULL; 
    q[head++]=root; 
    while(head!=tail)
	{ 
        node *temp=q[tail++]; 
        node *p=NULL; 
        for(i=0;i<26;i++)
		{ 
            if(temp->next[i]!=NULL)
			{ 
                if(temp==root)//第二层 
				    temp->next[i]->fail=root;                 
                else
				{
				    p=temp->fail;//父结点的失败指针 
                    while(p!=NULL)
					{  
                        if(p->next[i]!=NULL)// 
					    { 
                            temp->next[i]->fail=p->next[i]; 
                            break; 
                        } 
                        p=p->fail; 
                    } 
                    if(p==NULL)//p为root结点 
					    temp->next[i]->fail=root; 
                } 
                q[head++]=temp->next[i];//入队列  
            } 
        }   
    } 
}


/*匹配: 匹配过程分两种情况:(1)当前字符匹配,表示从当前节点沿着树边有一条路径可以到达目标字符,
此时只需沿该路径走向下一个节点继续匹配即可,目标字符串指针移向下个字符继续匹配;
(2)当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,匹配过程随着指针指向root结束。
重复这2个过程中的任意一个,直到模式串走到结尾为止。*/ 
int query(node *root){ 
    int i=0,cnt=0,index,len=strlen(str); 
    node *p=root;  
    while(str[i])
	{  
        index=str[i]-'a';  
        while(p->next[index]==NULL && p!=root) p=p->fail; 
        p=p->next[index]; 
        p=(p==NULL)?root:p; 
        node *temp=p; 
        while(temp!=root && temp->count!=-1)
		{ 
            cnt+=temp->count; 
            temp->count=-1; 
            temp=temp->fail; 
        } 
        i++;                 
    }    
    return cnt; 
}




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值