AC多模匹配+完整实现源码
前段时间同事讲了一下AC多模匹配的原理,就试着写了下代码,现在再看代码的时候有些地方连自己都快看不懂了,所以想做一个笔记
查找10M的日志文件,即使最后一行,用时不到0.2毫秒能正确查找出ssss串中的s,ss,sss,ssss个数和位置,notepad无法实现
1、构建树
构建模式串(需要搜索的串)为{"hee","he", "h","she", "his" ,"her","hers"}的树。注:下划线序号表示层高
构建过程也是查找的过程,举例讲解构建:hee过程,其他类似
构建hee过程:
1、构建h节点:输入串为h,以根节点作为起始节点SNode,查找SNode下是否存在值为h,层高为strlen(h)=1的节点,不存在,插入
2、构建第一个e节点:输入串为he,以根节点作为起始节点SNode,查找SNode下是否存在值为h,层高为strlen(h)=1的节点,存在,以h节点作为SNode,查找是否存值为e,层高为strlen(he)的节点,不存在,插入
3、构建第二个e节点:输入串为hee,以根节点作为起始节点SNode,查找SNode下是否存在值为h,层高为strlen(h)=1的节点,存在,以h节点作为SNode,查找是否存值为e,层高为strlen(he)的节点,存在,以e节点作为SNode节点,查找是否存值为e,层高为strlen(hee)的节点,不存在,插入。构建字符e为构建串的最后一个字符时,该节点为输出节点
构建一个串中某个字符的节点时,会将该字符的前面所有字符+该字符作为一个串输入,搜索树并插入。因为每个字符必须要知道前面的路径
2、构建失败节点
- 根节点的失败节点为根节点,第一层节点的失败节点为根节点
- 某个节点的失败节点为:以该节点的父节点的失败节点为起点查找该节点,如果能找到,找到的节点为失败节点,不能找到,则失败节点为根节点
已知: f(root) = root;f(h_1)=root;f(s_1)=root
解: f(e_2) = g(f(h_1),e) = g(root,e) = root
f(e_3) = g(f(e_2),e) = g(root,e) = root
f(r_3) = g(f(e_2),r) = g(root,r) = root
f(s_4) = g(f(r_3),s) = g(root,s) = s_1
f(i_2) = g(f(h_1),i) = g(root,i) = root
f(s_3) = g(f(i_2),s) = g(root,s) = s_1
f(h_2) = g(f(s_1),h) = g(root,h) = h_1
f(e_3) = g(f(h_2),e)=g(h_1,e)=e_2
3、查找"ushers"中的模式串
1、遍历"ushers",从根节点作为起始节点SNode,查找字符为u的节点,查找失败,以SNode的失败节点为起始节点查找下一个字符s
2、以SNode作为起始节点,查找字符为s的节点,查找成功,判断节点是否为匹配节点,输出匹配值,以s节点作为起始节点查找h节点,直到遍历完"ushers"
大家可以手动试一下构建模式串为{"s","ss","sss","ssss"}的树,构建每个节点的失败节点,并在内容"ssss"中查找模式串
文字只讲了大致流程,还有很多细节没有描述出来,语言水平有限啊,细节大家看代码吧...
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AC.h
#ifndef AC_H #define AC_H #define MAX_CHILD_LEN 128 #define MAX_OUTPUT 128 #include <string.h> #include <stdio.h> class Node { public:Node(char ele){element = ele;parent = NULL;failNode = NULL;isMatchNode=false;memset(nodeList,0,MAX_CHILD_LEN);childNum=0;high = 0;memset(outPut,0,MAX_OUTPUT);outPutNum = 0;}~Node(){printf("node release,high:%d value:%c\n",high,element);for(int i=0;i<outPutNum;i++){char * ele = outPut[i];printf("release output str:%s\n",ele);delete ele;ele = NULL;}}char element;Node * parent;Node * nodeList[MAX_CHILD_LEN];Node * failNode;bool isMatchNode;int childNum;int high;char * outPut[MAX_OUTPUT];int outPutNum; }; typedef void(*Func)(char * matchedStr,int post); class AC { public:AC() {root = new Node(NULL);root->failNode = root;}~AC(){delete root;root = NULL;}void initTree(char * patterns[],int patLen){for(int i=0;i<patLen;i++){char * element = patterns[i];int eleLen = strlen(element);for(int j=0;j<eleLen;j++){bool isMatch = false;if(j == eleLen-1)isMatch = true;char * p = new char[j+2];memset(p,'\0',j+2);strncpy(p,element,j+1);insert(p,isMatch);}}}void buildFailNode(){traceAllNodes(root);}void match(char * srcTxt,int txtLen,Func f){Node * startNode = root;for(int i=0;i<txtLen;i++){char e = srcTxt[i];bool isOk = false;for(int j=0;j<startNode->childNum;j++){Node * node = startNode->nodeList[j];if(node->element == e){isOk = true;startNode = node;Node * failNode = node->failNode;while(failNode!=root){if(failNode->isMatchNode){for(int k=0;k<failNode->outPutNum;k++)f(failNode->outPut[k],i);}failNode = failNode->failNode;}if(node->isMatchNode){for(int k=0;k<node->outPutNum;k++)f(node->outPut[k],i);}break;}}if(!isOk){startNode = startNode->failNode;if(startNode!=root)i--;}}}void deleteTree(){printf("delete tree--------------------------------\n");traceDelNodes(root);}void printACTree(){printf("tree structure-----------------------------\n");printf("high value match failNode childNum children outPutStr \n");tracePrintNodes(root);} private:void insert(char * ele,bool isMatch){int eleLen = strlen(ele);//搜索ele最后一个元素节点是否存在,不存在则返回父节点int startH = 1;Node * pnode = NULL;if(!search(root,startH,ele,pnode)){Node * cnode = new Node(ele[eleLen-1]);cnode->high = eleLen;cnode->parent = pnode;cnode->isMatchNode = isMatch;pnode->nodeList[pnode->childNum]=cnode;pnode->childNum++;if(isMatch)cnode->outPut[cnode->outPutNum++]=ele;}}bool search(Node * pnode,int & index,char * ele,Node * &retNode){for(int i=0;i<pnode->childNum;i++){Node * node = pnode->nodeList[i];if(node->element == ele[index-1]){if(index == strlen(ele))return true;index++;return search(node,index,ele,retNode);}}retNode = pnode;return false;}void initFailNode(Node * node){if(node->high == 1){node->failNode = root;}else{//以父节点的失败函数作为起点,node的element作为触发边得到node的失败函数Node * failNode = NULL;searchFailNode(node->parent,node,failNode);node->failNode = failNode;}}void traceAllNodes(Node * node){for(int i=0;i<node->childNum;i++){Node * cnode = node->nodeList[i];initFailNode(cnode);traceAllNodes(cnode);}}void searchFailNode(Node * pnode,Node * cnode,Node * & retNode){Node * failNode = pnode->failNode;for(int i=0;i<failNode->childNum;i++){Node * node = failNode->nodeList[i];if(node->element == cnode->element){retNode = node;return;}}//循环已经走完,说明没找到节点,如果已经搜索了根节点没找到,则返回根节点作为失败节点,否则继续搜索if(pnode->failNode == root)retNode = root;elsesearchFailNode(pnode->parent,pnode,retNode);}void tracePrintNodes(Node *node){for(int i=0;i<node->childNum;i++){Node * cnode = node->nodeList[i];printf(" %d %c %d %d %d ",cnode->high,cnode->element,cnode->isMatchNode,cnode->failNode->high,cnode->childNum);for(int j=0;j<cnode->childNum;j++){Node * lnode = cnode->nodeList[j];printf("%c ",lnode->element);}printf(" ");for(int j=0;j<cnode->outPutNum;j++)printf("%s ",cnode->outPut[j]);printf("\n");tracePrintNodes(cnode);}}void traceDelNodes(Node * node){for(int i=0;i<node->childNum;i++){Node * cnode = node->nodeList[i];traceDelNodes(cnode);}if(node!=root){delete node;node = NULL;}} private:Node * root; }; #endif // AC_H----------------------------------------------------------------------------------- main.cpp #include "AC.h" #include <time.h> #include <sys/time.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <map> #define MAX_FILE_CONTENT 1024*1024*20 void currentTime(char * timeOutPut,int timeLen){time_t t = time(NULL);struct tm * timeinfo = localtime(&t);strftime (timeOutPut,timeLen,"%Y-%m-%d %H:%M:%S:",timeinfo);struct timeval tval;gettimeofday(&tval,NULL);sprintf(timeOutPut+strlen(timeOutPut),"%d",tval.tv_usec/1000); } //回调函数在外面进行统计,找到一个回调一次 void findCallBack(char * matchedStr,int startPos){char curTime[32]={0};currentTime(curTime,sizeof(curTime));printf("end time:%s matchedStr:%s matchedPos:%d\n",curTime,matchedStr,startPos); } bool readFile(char * fileName,char * fileContent){int fd = open(fileName,O_RDONLY);if(-1 == fd){printf("open file error:%d\n",errno);return false;}int len = read(fd,fileContent,MAX_FILE_CONTENT);if(-1 == len){printf("read file error:%d\n",errno);close(fd);return false;}close(fd);return true; } void ac_func(char ** pattern,int patLen,char *txt,int txtLen){AC ac;ac.initTree(pattern,patLen);ac.buildFailNode();ac.printACTree();char curTime[32]={0};currentTime(curTime,sizeof(curTime));printf("searching tree-----------------------------\n");printf("start time of search:%s\n",curTime);ac.match(txt,txtLen,findCallBack);ac.deleteTree(); } void test1(){char *pattern[]={"hee","he", "h","she", "his" ,"her","hers"};char *txt = "ushers";int patternLen = sizeof(pattern)/sizeof(char*);int txtLen = strlen(txt);ac_func(pattern,patternLen,txt,txtLen); } void test2(){//模式串出现的顺序在文件中刚好相反,里面存在一个关键字在日志文件的最后一行char * pattern[] = {"39_347990193541512029","39_347739859976612007","13_1002D375","2017-09-29 17:43:37:517"};//文件内容太大,使用堆内存char * txt = new char[MAX_FILE_CONTENT];bzero(txt,MAX_FILE_CONTENT);//test.log为一个10M的日志if(!readFile("../testfile/test.log",txt))return;int patternLen = sizeof(pattern)/sizeof(char*);int txtLen = strlen(txt);ac_func(pattern,patternLen,txt,txtLen);delete txt;txt = NULL; } void test3(){//模式串和内容出现自包含,notepad遇到这样的搜索有bugchar *pattern[]={"s", "ss","sss","ssss"};char *txt = "ssss";int patternLen = sizeof(pattern)/sizeof(char*);int txtLen = strlen(txt);ac_func(pattern,patternLen,txt,txtLen); } int main() {test1();test2();test3();return 0; }
---------------------------------------------------------------------------------------------------- 运行结果部分截图
转载于:https://www.cnblogs.com/dosomethingyoulike/p/8076348.html
AC多模匹配+完整实现源码相关推荐
- Matlab实现PSO算法(附上6个完整仿真源码)
PSO(Particle Swarm Optimization)是一种优化算法,它模拟了鸟群或鱼群等动物的集体行为,通过群体智能的方式来解决优化问题.PSO算法最初由Kennedy和Eberhart在 ...
- 流浪猫流浪狗H5完整运营源码下载/可封装APP
简介: 流浪猫流浪狗H5完整运营源码下载/可封装APP 适合做猫狗宠物类的发信息发布. 当然其他信息发布也是可以的. 刚刚开发出炉的!亲测可用 网盘下载地址: http://kekewangLuo.n ...
- 梦幻诛仙linux纯端架设教程,梦幻诛仙 一键端搭建iOS安卓双端+完整后台源码+各种工具附带视频架设教程...
游戏说明: 梦幻诛仙一键端搭建iOS安卓双端+完整后台源码+各种工具,视频架设教程 在游戏内当前聊天窗口输入 dmmhzxnb ,开启后台. 提示GM后台已开启. 在左上角Press Enter ...
- 新阿阳发卡网完整运营源码
介绍: 新阿阳发卡网完整运营源码/小白版一键配置直装版+接入免签支付接口+视频搭建教程 也是一款非常完整的发卡网,功能都正常好用,接入微信支付宝双免签通道,这个手机端的配色和UI我个人挺喜欢的,很漂亮 ...
- 【2022修复版】社群扫码进群活码引流完整运营源码/带视频搭建教程
搭建环境 1.环境Nginx MySQL 5.6 php7.2 php7.2安装扩展fileinfo redis Swoole sg11 服务器需要安装linux的系统, 安装上宝塔,在配置这些环境就 ...
- Unity小游戏-平衡大师(安卓、PC、web)2D益智类游戏 项目展示+完整项目源码
游戏录像 游戏试玩 平衡带师_平衡带师html5游戏_4399h5游戏-h.4399.com 游戏玩法 这是一款类似堆积木的游戏,它非常考验玩家的智商和手速,难度系数很高的游戏,谁能征服它,谁就是平衡 ...
- 维吉尼亚密码破解(Python完整详细源码)
维吉尼亚密码破解(Python完整详细源码) 欢迎大家访问我的GitHub博客 https://lunan0320.github.io/ 文章目录 维吉尼亚密码破解(Python完整详细源码) 1.写 ...
- Matlab实现遗传算法(附上完整仿真源码)
遗传算法(Genetic Algorithm,GA)是一种基于生物进化理论的优化算法,通过模拟自然界中的遗传过程,来寻找最优解. 在遗传算法中,每个解被称为个体,每个个体由一组基因表示,每个基因是解空 ...
- 最新云豹二开直/播短视频完整系统源码+带开发文档/教程
正文: 最新云豹二开直/播短视频完整系统源码+带开发文档/教程,好友给我分享的,属于云豹二开,功能非常的强大,且有非常完整的开发文档和教程. 但是说实话这类程序不属于好部署的那一种,比较吃一定的技术, ...
最新文章
- git报错:remote: warning: Large files detected.
- 关系数据库中,表中的每行就是一个对象
- opencv 叠加文字_Hello world.
- 第一:Python操作MySQL数据库
- MSAgent 详细解说(下)
- Padavan完整编译教程
- vs2017社区版在离线的电脑上注册方法
- SVM 超平面计算例题
- 高频引力波数值计算matlab,李刚李莉张雏黄敬霞受热变形及系统优化分析J光.doc...
- laravel 实现app支付宝退款
- Win10下媲美apt的包管理工具 Scoop 的安装以及常用软件清单
- 边缘设备上的计算机视觉
- 1.5 日本の会社で働くのは、初めてなので、不安です
- 开放平台成网络淘金下一站 从圈地到吸纳盟友
- c# Winform实现中国省份地图
- 前端 H5 横屏 独特处理方案详解
- IIC总线协议,7位,8位,10位地址
- sql结果集进行诸如求并集,交集等操作
- Android开发第三方支付微信支付实例集成过程介绍
- 关于2022年卡塔尔世界杯