最近作了一项工做:容许一个 DFA 有多个起始状态(能够称做根: root)。引入这个概念有不少好处,主要体如今 DFA Union 中,这个操做经过 NFA 到 DFA 的转化来完成,算法思想很简单:正则表达式
建立一个 NFA,该 NFA 只有初始状态是非肯定 (non-DFA) 状态:初始状态只有 ε 转移,这些 ε 转移指向全部要被 Union 的 DFA 的初始状态,而后将该 NFA 转化为 DFA。算法
由于 NFA 转化 DFA 是 NSpace 的,虽然不少数状况下只有线性复杂度,咱们仍然但愿尽量减少这个复杂度。性能
在建立多正则表达式匹配的 DFA 的过程当中,就有一个 DFA 的 Union 操做,在这个过程当中,若是状态膨胀失去控制,须要使用某种方式对正则表达式集合进行分组,以便抑制这种状态膨胀。分组后会生成多个 DFA ,可是为了应用程序接口方便统一,将这多个 DFA 揉进一个 DFA 对象,每一个分组的 DFA 就须要一个不一样的初始状态(根)。优化
虽然以前我也曾想过 DFA 包含多个初始状态(根)的可能性,但一直没有深刻思考,此次通过仔细思考,发现:对于(全部的) DFA 最小化算法,从理论上讲,彻底没有必要限制为单根 DFA,无论有多少个根,算法都能正常工做!惟一须要注意的是,最小化先后的根,在某些应用中须要一一对应起来。ui
最小化以前的多根 DFA 能够彻底是独立的,惟一的要求是全部 DFA 的状态 ID 属于同一个 ID 空间,这很简单,工程上用同一个 DFA 对象来表达便可,对于 分离的多个 DFA 对象,只须要实现一个 DFA 包装器,将多个分离的 DFA 的状态 ID 从新映射便可。spa
如此,就完成了执行多根 DFA 最小化的全部准备。最小化完成以后,这些多个 DFA 会共享一些相同的尾部,通常状况下,头部不会共享;不过极端状况下,例如 DFA1 是 DFA2 的子集,那么,从 DFA2 的根就能到达 DFA1 的根,此时整个 DFA1 就被彻底共享了。.net
全部的尾部都被最小化了,而后再用 NFA 转化 DFA 的方式执行最小化,这样,大大减少了 NFA 转 DFA 的时间和内存消耗。对象
细节可参考:多正则表达式匹配 (Multiple Regular Expression Matching) 中的动态 DFA 算法blog
主要有两点:在实现这个概念的过程当中,对个人 adfa_minimize 作了一些重构,同时也进行了一些优化。接口