AC自动机简易版

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

应该是最后一次修改了吧 ,最后还是把完全包含情况记入了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; 
}



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值