前段时间同事讲了一下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、构建失败节点

  1. 根节点的失败节点为根节点,第一层节点的失败节点为根节点
  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多模匹配+完整实现源码相关推荐

  1. Matlab实现PSO算法(附上6个完整仿真源码)

    PSO(Particle Swarm Optimization)是一种优化算法,它模拟了鸟群或鱼群等动物的集体行为,通过群体智能的方式来解决优化问题.PSO算法最初由Kennedy和Eberhart在 ...

  2. 流浪猫流浪狗H5完整运营源码下载/可封装APP

    简介: 流浪猫流浪狗H5完整运营源码下载/可封装APP 适合做猫狗宠物类的发信息发布. 当然其他信息发布也是可以的. 刚刚开发出炉的!亲测可用 网盘下载地址: http://kekewangLuo.n ...

  3. 梦幻诛仙linux纯端架设教程,梦幻诛仙 一键端搭建iOS安卓双端+完整后台源码+各种工具附带视频架设教程...

    游戏说明: 梦幻诛仙一键端搭建iOS安卓双端+完整后台源码+各种工具,视频架设教程 在游戏内当前聊天窗口输入  dmmhzxnb ,开启后台.  提示GM后台已开启. 在左上角Press Enter ...

  4. 新阿阳发卡网完整运营源码

    介绍: 新阿阳发卡网完整运营源码/小白版一键配置直装版+接入免签支付接口+视频搭建教程 也是一款非常完整的发卡网,功能都正常好用,接入微信支付宝双免签通道,这个手机端的配色和UI我个人挺喜欢的,很漂亮 ...

  5. 【2022修复版】社群扫码进群活码引流完整运营源码/带视频搭建教程

    搭建环境 1.环境Nginx MySQL 5.6 php7.2 php7.2安装扩展fileinfo redis Swoole sg11 服务器需要安装linux的系统, 安装上宝塔,在配置这些环境就 ...

  6. Unity小游戏-平衡大师(安卓、PC、web)2D益智类游戏 项目展示+完整项目源码

    游戏录像 游戏试玩 平衡带师_平衡带师html5游戏_4399h5游戏-h.4399.com 游戏玩法 这是一款类似堆积木的游戏,它非常考验玩家的智商和手速,难度系数很高的游戏,谁能征服它,谁就是平衡 ...

  7. 维吉尼亚密码破解(Python完整详细源码)

    维吉尼亚密码破解(Python完整详细源码) 欢迎大家访问我的GitHub博客 https://lunan0320.github.io/ 文章目录 维吉尼亚密码破解(Python完整详细源码) 1.写 ...

  8. Matlab实现遗传算法(附上完整仿真源码)

    遗传算法(Genetic Algorithm,GA)是一种基于生物进化理论的优化算法,通过模拟自然界中的遗传过程,来寻找最优解. 在遗传算法中,每个解被称为个体,每个个体由一组基因表示,每个基因是解空 ...

  9. 最新云豹二开直/播短视频完整系统源码+带开发文档/教程

    正文: 最新云豹二开直/播短视频完整系统源码+带开发文档/教程,好友给我分享的,属于云豹二开,功能非常的强大,且有非常完整的开发文档和教程. 但是说实话这类程序不属于好部署的那一种,比较吃一定的技术, ...

最新文章

  1. git报错:remote: warning: Large files detected.
  2. 关系数据库中,表中的每行就是一个对象
  3. opencv 叠加文字_Hello world.
  4. 第一:Python操作MySQL数据库
  5. MSAgent 详细解说(下)
  6. Padavan完整编译教程
  7. vs2017社区版在离线的电脑上注册方法
  8. SVM 超平面计算例题
  9. 高频引力波数值计算matlab,李刚李莉张雏黄敬霞受热变形及系统优化分析J光.doc...
  10. laravel 实现app支付宝退款
  11. Win10下媲美apt的包管理工具 Scoop 的安装以及常用软件清单
  12. 边缘设备上的计算机视觉
  13. 1.5 日本の会社で働くのは、初めてなので、不安です
  14. 开放平台成网络淘金下一站 从圈地到吸纳盟友
  15. c# Winform实现中国省份地图
  16. 前端 H5 横屏 独特处理方案详解
  17. IIC总线协议,7位,8位,10位地址
  18. sql结果集进行诸如求并集,交集等操作
  19. Android开发第三方支付微信支付实例集成过程介绍
  20. 关于2022年卡塔尔世界杯

热门文章

  1. Druid监控页面的配置和使用
  2. Ubuntu 21.04(arm64) 基于sanp安装Nextcloud,挂载本地硬盘
  3. AForge学习笔记(10):AForge.Imaging.Filters
  4. Pantera Capital创始合伙人:最大遗憾是没有投资以太坊ICO
  5. win7系统笔记本做无线路由器
  6. win10下安装多个JDK配置方法
  7. Mysql 中 case when then else end 用法
  8. openwrt的UCI 网络配置与Luci在线安装
  9. session和token鉴权
  10. 软件项目中的质量管理