应该是最后一次修改了吧 ,最后还是把完全包含情况记入了ac内部,当构建fail指针的时候,
比如 abcd 与bc 当构建到 abcd的c的时候,检测到bc的c为终止态,就将bc的c的终止态信息添加到abcd的c上面去,解决了这一个问题.
还有修复了之前的查找问题,如果查找不到parent的fail->next的信息就直接指向parent的fail,这种是不对的,应该直接指向root
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
修改了一次,添加了可扩展的接口,使接口可以传递自定义参数进行控制,编写回调接口.同时放弃strlen的内部调用,使函数可以完全的面向二进制流
但是ac好像本身就有一个缺陷,就是如果添加的字串中,如果存在完全包含关系,必须得外部特例写出来或者内部实现时写出来
比如两个串 abcd bc,在cabcde中搜索,是只能搜出abcd而不能搜出bc来的,不知道是我写法上应该在添加字符串时,将bc添加到abcd中去识别 还是在外部额外去处理,还有待研究,个人觉得这种特例外部实现比内部实现要效果好些
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
一言不合就贴代码
基于单字节流的二级制多模匹配算法
效果截图
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
extern "C" {
const int kind = 256;
const int chongfu=20; //单字符最大重复次数
typedef int(*ACcallack)(int pos,int id,void*);
/*
主要ac结构体
*/
struct node{
unsigned char id;
node *fail;
node *next[kind];
int count;
int result[chongfu];
};
struct node* bznode()
{
node *t=(struct node*)malloc(sizeof(struct node));
if(t)
memset(t,0,sizeof(node));
return t;
}
/*
广度优先搜索算法结构体
*/
struct FBSnode{
unsigned char id;
struct node* parent;
struct node* curnode;
struct FBSnode* next;
FBSnode(){parent=0;next=0;id=0;}
};
struct FBSnode* bzfbsnode()
{
struct FBSnode*t=(struct FBSnode*)malloc(sizeof(struct FBSnode));
if(t)
memset(t,0,sizeof(struct FBSnode));
return t;
}
/*
添加字符
*/
void insertchar(unsigned char ch,int is_end,int id,node **leafhead)
{
node *leaf=*leafhead;
if(leaf==0)
{
*leafhead= bznode();
leaf=*leafhead;
}
if(leaf->next[ch]==0)
{
leaf->next[ch]=bznode();
leaf->next[ch]->id=ch;
if(is_end!=0)
{
leaf->next[ch]->count=1;
leaf->next[ch]->result[0]=id;
}
}
else
{
if(is_end!=0)
{
leaf->next[ch]->result[ leaf->next[ch]->count++]=id;
}
}
}
/*
添加字符串
*/
void insert(unsigned char *str,int len,int id,node **root)
{
node **p=root;
int i=0,index;
for(i=0;i<len;i++)
{
index=str[i];
insertchar(*(unsigned char*)&str[i],i==len-1?1:0,id,p);
p=&((*p)->next[index]);
}
}
/*
构建fail表
*/
void addresid(node**leaf,node **leafcopy)
{
int j;
int id;
if((*leafcopy)->count!=0)
{
for(j=0;j<(*leafcopy)->count;j++)
{
id=(*leafcopy)->result[j];
if((*leaf)->count==0)
{
(*leaf)->count=1;
(*leaf)->result[0]=id;
}
else if((*leaf)->count<chongfu)
{
(*leaf)->result[(*leaf)->count]=id;
(*leaf)->count++;
}
else
{
//log(out of memery);
return ;
}
}
}
}
void build(node *root)
{
int i,j;
FBSnode *headnode=bzfbsnode();
FBSnode *cur=0;
headnode->curnode=root;
headnode->parent=root;
FBSnode *endnode=headnode;
root->fail=root;
for(i=0;i<kind;i++) //将root fail 指向自己 同时将一级子节点指向root
{
if(root->next[i]!=0)
{
root->next[i]->fail=root;
for(j=0;j<kind;j++)
{
if(root->next[i]->next[j]!=0)
{
endnode->next=bzfbsnode();
endnode=endnode->next;
endnode->curnode=root->next[i]->next[j];
endnode->parent=root->next[i];
endnode->id=j;
}
}
}
}
cur=headnode;
do //从二级子节点开始fail表构建
{
cur=cur->next;
if(cur->parent->fail->next[cur->id]!=0)
{
cur->curnode->fail=cur->parent->fail->next[cur->id];
//cur->curnode->fail=cur->parent->fail;
addresid(&cur->curnode,&cur->parent->fail->next[cur->id]);
}
else
{
cur->curnode->fail=root;
}
for(j=0;j<kind;j++)
{
if(cur->curnode->next[j]!=0)
{
endnode->next=bzfbsnode();
endnode=endnode->next;
endnode->curnode=cur->curnode->next[j];
endnode->parent=cur->curnode;
endnode->id=j;
}
}
}while(cur!=endnode);
cur=headnode->next;
while(cur!=0)
{
free(headnode);
headnode=cur;
cur=cur->next;
}
}
/*
查询字符串
str 目标字符串
root 构建完毕的ac树
function ac查找时找到的回调函数 (int 返回值为0 继续查找 为1 直接完成查找 ,第一个参数int 位置,第二个参数 id ,第三个参数 待扩展
data 传递给function的参数 扩展做控制使用
*/
void query(unsigned char* str,int len ,node *root,ACcallack function,void*data)
{
int i=0,j=0;
node *p=root;
for(i=0;i<len;i++)
{
if(p->next[str[i]]==0)
{
if(p->fail->next[str[i]]!=0)
p=p->fail->next[str[i]];
else
//p=p->fail;
p=root;
}
else
{
p=p->next[str[i]];
}
for(j=0;j<p->count;j++)
{
if(function(i,p->result[j],data)==1)
{
return ;
}
}
}
}
}
#ifdef __CPlusPlus__
namespace ACspace{
class ACbin{
public:
ACbin(){root=0;}
void binquery(unsigned char* str,int len ,ACcallack function,void*data)
{
if(root!=0)
query(str,len,root,function,data);
}
void insert(unsigned char *str,int len,int id)
{
node **p=&root;
int i=0,index;
for(i=0;i<len;i++)
{
index=str[i];
insertchar(*(unsigned char*)&str[i],i==len-1?1:0,id,p);
p=&((*p)->next[index]);
}
}
void acbuild()
{
build(root);
}
struct node* root;
};
}
using namespace ACspace;
#endif
char *str="cabcdefghijklmn";
int myACcallack(int pos,int id,void*)
{
char tmp[1024];
memcpy(tmp,str,pos+1);
tmp[pos+1]=0;
printf("%d\t%d\t%s\n",pos,id,tmp);
return 0;
}
void myinsert(char *str,int id,node**root)
{
insert((unsigned char*)str,strlen(str),1,root);
}
int main()
{
node *root=0;
myinsert("ab",1,&root);
myinsert("bc",2,&root);
myinsert("eabce",3,&root);
myinsert("abcd",4,&root);
myinsert("mjamec",5,&root);
myinsert("mjamed",6,&root);
build(root);
query((unsigned char*)str,strlen(str),root,myACcallack,0);
#ifdef __CPlusPlus__
ACbin myac;
myac.insert((unsigned char*)"ab",2,1);
myac.insert((unsigned char*)"bc",2,2);
myac.insert((unsigned char*)"eabce",5,3);
myac.insert((unsigned char*)"abcd",4,4);
myac.acbuild();
myac.binquery((unsigned char*)str,strlen(str),myACcallack,0);
#endif
getchar();
return 0;
}

本文详细介绍了AC自动机的优化实现过程,包括解决完全包含模式的问题、修复查找缺陷,并添加了可扩展接口以增强灵活性。通过代码示例展示了如何构建失败指针、添加字符串以及查询目标字符串。
1307

被折叠的 条评论
为什么被折叠?



