ac算法--c++实现

604 篇文章 8 订阅
579 篇文章 5 订阅
注:由于代码中使用了,对象初始化,所以编译的时候必须使用g++,但是可以修改掉C++内容,编程纯c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
 
 
const int MAXQ = 500000+10;
const int MAXN = 1000000+10;
const int MAXK = 26; //自动机里字符集的大小
struct TrieNode
{
      struct TrieNode* fail;
      struct TrieNode* next[MAXK];
       bool danger;   //该节点是否为某模式串的终结点
       int cnt;    //以该节点为终结点的模式串个数
       TrieNode()
       {
              fail = NULL;
              memset(next, 0, sizeof(next));
              danger = false;
              cnt = 0;
       }
}*que[MAXQ], *root;
//文本字符串
char msg[MAXN];
int   N;
void TrieInsert(char *s)
{/*建立goto表*/
       int i = 0;
       TrieNode *ptr = root;
       while(s[i])
       {
              int idx = s[i]-'a';
              if(ptr->next[idx] == NULL)
                     ptr->next[idx] = new TrieNode();
              ptr = ptr->next[idx];
              i++;
       }
       ptr->danger = true;
       ptr->cnt++;
}
 
void Init()
{
       int i;
       char s[100];
       char a1[10]="she";
       char a2[10]="his";
       char a3[10]="hers";
       char a4[10]="he";
       
       root = new TrieNode();
       //scanf("输入待匹配的字符串个数:%d", &N);
       //for(i = 0; i < 4; i++)
       //{
              //scanf("输入第%d个带匹配字符串%s",i, s);
              
              TrieInsert(a1);
              TrieInsert(a2);
              TrieInsert(a3);
              TrieInsert(a4);
       //}
}
 
void Build_AC_Automation()
{
       int rear = 1, front = 0, i;
       que[0] = root;
       root->fail = NULL;
       while(rear != front)
       {
              TrieNode *cur = que[front++];
              for(i = 0; i < 26; i++)
                     if(cur->next[i] != NULL)
                     {
                            if(cur == root)
                                   cur->next[i]->fail = root;
                            else
                            {
                                   TrieNode *ptr = cur->fail;
                                   while(ptr != NULL)
                                   {
                                          if(ptr->next[i] != NULL)
                                          {/*建立fail表,所有新单词从第一个字母开始建立,无匹配则跳转到开始节点,
                                          	下一个则从上一个字母的fail表匹配,如此则避免了重新划分最长后缀--空间换时间*/
                                                 cur->next[i]->fail = ptr->next[i];
                                                 if(ptr->next[i]->danger == true)
                                                        cur->next[i]->danger = true;
                                                 break;
                                          }
                                          ptr = ptr->fail;
                                   }
                                   if(ptr == NULL) cur->next[i]->fail = root;
                            }
                            que[rear++] = cur->next[i];
                     }
       }
}
int AC_Search()
{
       int i = 0, ans = 0;
       TrieNode *ptr = root;
       while(msg[i])
       {
              int idx = msg[i]-'a';
              while(ptr->next[idx] == NULL && ptr != root) ptr = ptr->fail;
              ptr = ptr->next[idx];
              if(ptr == NULL) ptr = root;/*非终点字符串,有未匹配的时候,直接跳转到起点重新匹配*/
              TrieNode *tmp = ptr;
              while(tmp != NULL && tmp->cnt != -1)
              {
                     ans += tmp->cnt;/*这里只计算第一次命中某字段*/
                     tmp->cnt = -1;/*已经命中过的字符串,所有output表全部清空*/
                     tmp = tmp->fail;/*终点字符串直接查找跳转表*/
              }
              i++;
       }
       return ans;
}
int main()
{
       int T = 2;
      // scanf("输入待检查的字符串个数:%d", &T);
       while(T--)
       {
              Init();
              Build_AC_Automation();
              //文本
              //scanf("输入待检查的字符串:%s", msg);
              strcpy(msg,"i am shenjinwei,he not hers, is a man");
              printf("总共有%d个字符串可以匹配上\n", AC_Search());
       }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值