Python算法实践——AC自动机
来源:互联网 发布:js 数组元素 函数 编辑:程序博客网 时间:2024/06/16 03:56
由于平时编程项目时会用到Python,索性就自学了一段时间,发现Python还是很好用的,有点爱不释手。第一篇博客就献给AC自动机,这也是我所见过的神奇算法之一。
AC自动机是一种多模匹配算法,所谓多模匹配,就是模式串有多个。其主要的步骤分为三步:
1.用模式串建立字典树
字典树(Trie树)是一种变种的哈希数,存放字符串非常方便,查找效率也比较高。字典树中存放的字符串即是从根到叶子路径上所有结点值,每次插入新的字符串,在遍历字符串的同时,从根结点开始查找,若字符出现在当前结点的子结点,则转到子结点继续查找下一个字符,否则将该字符插到当前结点的子结点中。这里Python语言由于没有C/C++的结构体,所以使用类来构建出结点类。此外使用LIST类型来存放结点的子结点。
2.KMP处理
提到模式匹配,KMP肯定是不能少的。KMP中优化的核心便是NEXT数组,其每次匹配失败时均根据NEXT数组选择合适的位置开始匹配 ,而不是从头开始。同样的策略自动机也有,在自动机中,我们是Fail指针指向一个结点,当匹配失败时,则转到该结点的Fail结点继续回溯。
3.模式匹配
在AC自动机建立好后,就可以在自动机上匹配字符串上了,另外Python3默认使用兼容ASCII的UTF-8编码,简化了Python2中的编码问题,所以中文也是可以匹配的。
附上Python3代码:
#结点类class node: def __init__(self,ch): self.ch = ch #结点值 self.fail = None #Fail指针 self.tail = 0 #尾标志:标志为 i 表示第 i 个模式串串尾 self.child = [] #子结点 self.childvalue = [] #子结点的值 #AC自动机类class acmation: def __init__(self): self.root = node("") #初始化根结点 self.count = 0 #模式串个数 #第一步:模式串建树 def insert(self,strkey): self.count += 1 #插入模式串,模式串数量加一 p = self.root for i in strkey: if i not in p.childvalue: #若字符不存在,添加子结点 child = node(i) p.child.append(child) p.childvalue.append(i) p = child else : #否则,转到子结点 p = p.child[p.childvalue.index(i)] p.tail = self.count #修改尾标志 #第二步:修改Fail指针 def ac_automation(self): queuelist = [self.root] #用列表代替队列 while len(queuelist): #BFS遍历字典树 temp = queuelist[0] queuelist.remove(temp) #取出队首元素 for i in temp.child: if temp == self.root: #根的子结点Fail指向根自己 i.fail = self.root else: p = temp.fail #转到Fail指针 while p: if i.ch in p.childvalue: #若结点值在该结点的子结点中,则将Fail指向该结点的对应子结点 i.fail = p.child[p.childvalue.index(i.ch)] break p = p.fail #否则,转到Fail指针继续回溯 if not p: #若p==None,表示当前结点值在之前都没出现过,则其Fail指向根结点 i.fail = self.root queuelist.append(i) #将当前结点的所有子结点加到队列中 #第三步:模式匹配 def runkmp(self,strmode): p = self.root cnt = {} #使用字典记录成功匹配的状态 for i in strmode: #遍历目标串 while i not in p.childvalue and p is not self.root: p = p.fail if i in p.childvalue: #若找到匹配成功的字符结点,则指向那个结点,否则指向根结点 p = p.child[p.childvalue.index(i)] else : p = self.root temp = p while temp is not self.root: if temp.tail: #尾标志为0不处理 if temp.tail not in cnt: cnt.setdefault(temp.tail) cnt[temp.tail] = 1 else: cnt[temp.tail] += 1 temp = temp.fail return cnt #返回匹配状态 #如果只需要知道是否匹配成功,则return bool(cnt)即可 #如果需要知道成功匹配的模式串种数,则return len(cnt)即可
0 0
- Python算法实践——AC自动机
- 算法导论—AC自动机
- 算法模板——AC自动机
- 杭电ACM1277——全文检索~~AC自动机算法
- 经典算法题——第八题 AC自动机
- AC自动机2——KMP字符串匹配算法
- Aho-Corasick算法—Trie图(AC自动机)
- AC自动机算法与AC自动机专辑
- AC自动机算法与AC自动机专辑
- AC自动机算法
- AC自动机算法详解
- AC自动机算法详解
- AC自动机算法详解
- AC自动机算法
- AC自动机算法详解
- AC自动机算法详解
- AC自动机算法详解
- AC自动机算法
- Struts2框架学习 Day1
- 2016年终总结
- ztree --授权问题(根据ids) setting checked tree
- tomcat下禁用不安全的http方法
- Oracle优化05-执行计划
- Python算法实践——AC自动机
- 文章标题
- Docker与容器
- 内核调试
- Android进阶——自定义View之重写ViewGroup组合系统控件实现自定义ToolBar模板
- 在xml中如何引用自己定义的schema文件?
- 打酱油路过,2016年第四届湘潭大学新生趣味程序设计竞赛-Java
- C++ VS2010 一个解决方案下多个项目间的数据调用
- 2016就快结束了