模式匹配:AC自动机

一、概述

AC自动机在1975年产生于贝尔实验室,是著名的多模匹配算法之一。
之前谈到一种单模式匹配算法,KMP。与之比较,KMP是用来在一篇文章中匹配一个模式串;而假如存在多个模式串,按照KMP的思路就需要进行多轮重复匹配,所以这时候就需要一种更加有效率的方式。

AC自动机 = 字典树 + KMP

对于字典树和KMP算法不了解的,可以参考以下两篇博文:
1、字典树
2、KMP算法

二、基本原理

1、KMP和字典树

之前谈到,在KMP进行单模式匹配时,只需要线性的扫描一遍文本串,在扫描过程中出现匹配失败时,可以根据失配表,对移动位置进行确定,继续进行匹配。
而多模式的匹配需要怎么进行呢?考虑一下字典树,这是一种多模式的匹配,假如将多个模式串组合形成一个字典树,再结和KMP算法,这就是一种多模式匹配的思路了。

2、基本构造

按照上面的思路,将模式串处理称为字典树,对文本串进行匹配时,AC自动机应该具有三种状态:

(1)按字符匹配成功,继续匹配

从字典树的角度来说,就是当前节点的字符与文本串的字符相同,则继续按照字典树路径进行匹配

(2)按字符匹配成功,到达结尾

同样这里匹配成功后,但已经达到结尾,匹配结束

(3)按字符匹配失败

正常字典树匹配失败,则匹配结束。但结合了KMP算法中的失配表,AC自动机在匹配失败时,会进行路径跳转,通过失配路径进行进行匹配,直到匹配成功或者回到根节点

三、实例

以经典的ushers为例,模式串是[he、she、shr,say、her],文本串为‘ushers’

1、构建字典树

这里写图片描述

2、构造失配路径

这里写图片描述

步骤(1)节点'h'父节点为root节点,失配路径直接指向root节点

步骤(2)节点's'父节点为root节点,失配路径直接指向root节点

步骤(3)节点'e'父节点为'h',寻找节点'h'的前缀指针root节点,是否有字符为'e'的子节点,没有;
        前缀指针已为root节点,失配路径指向root节点

步骤(4)节点'a'父节点为's',寻找节点's'的前缀指针root节点,是否有字符为'a'的子节点,没有;
        前缀指针已为root节点,失配路径指向root节点

步骤(5)节点'h'父节点为's',寻找节点's'的前缀指针root节点,是否有字符为'h'的子节点,有;
        失配路径指向该字符为'h'的子节点

步骤(6)节点'r'父节点为'e'节点,寻找节点'e'的前缀指针root节点,是否有字符为'r'的子节点,没有;
        前缀指针已为root节点,失配路径指向root节点

步骤(7)节点'y'父节点为'a'节点,寻找节点'a'的前缀指针root节点,是否有字符为'y'的子节点,没有;
        前缀指针已为root节点,失配路径指向root节点

步骤(8)节点'e'父节点为'h'节点,寻找节点'h'的前缀指针'h'节点,是否有字符为'e'的子节点,有;
        失配路径指向该字符为'e'的子节点

步骤(9)节点'r'父节点为'h'节点,寻找节点'h'的前缀指针'h'节点,是否有字符为'r'的子节点,没有;
        继续寻找前缀指针节点'h'的前缀指针root节点,是否有字符为'r'的子节点,没有;

到这里,AC自动机的整个树就构造完毕了

3、匹配过程

自动从root节点出发,进行匹配,对于文本串‘ushers’:

(1)字符u在root节点的子节点无法找到,失配路径指向root节点

(2)字符s在root节点的子节点中存在,沿着字典树路径前进,到达's'节点

(3)字符h在's'节点的子节点中存在,沿着字典树路径前进,到达'h'节点

(4)字符e在'h'节点的子节点中存在,沿着字典树路径前进,到达'e'节点,输出she字符

(5)字符r在'e'节点的子节点中无法找到,失配路径指向前缀指针'e'节点;输出he字符
    字符r在前缀指针'e'节点中存在,沿着字典树路径前进,到达'r'节点,输出her字符

(6)字符s在'r'节点的子节点中无法找到,失配路径指向root节点

(7)匹配结束,输出字符为[she,he,her]

在上述步骤可以看到,算法在步骤5中,无法在子节点中找到字符r,此时会自动转向另一条路径,输出匹配成功的he及her字符;对于通过失配路径到达当前路径之后,状态机像从来没有走过之前的路径一样(从字典树上看,像直接从root节点出发到达),这样没有“失败”的从初始路径出发,直到匹配结束,体现相当高的效率。

猜你喜欢

转载自blog.csdn.net/sinat_33741547/article/details/79643301