算法之正则表达式匹配与NFA构建全解析

算法之正则表达式匹配与NFA构建全解析

在计算机科学领域,算法的学习与探索永无止境。我希望通过这篇博客,能和大家一起深入理解算法相关知识,在技术之路上共同进步。今天,我们聚焦于正则表达式匹配和非确定性有限自动机(NFA)构建这两个关键技术点,深入剖析其原理,并结合Java代码实例,让大家能轻松掌握这些复杂的概念。

一、正则表达式匹配的时间复杂度

在进行文本处理时,判断一个正则表达式能否识别一段文本是很常见的需求。有个重要的结论是:判定一个长度为M的正则表达式所对应的NFA能否识别一段长度为N的文本,在最坏情况下,所需时间和 (MN) 成正比。

这是怎么得到的呢?对于长度为N的文本中的每个字符,都要遍历一个大小不超过M的状态集合,还要在由E-转换构成的有向图中进行深度优先搜索。这个有向图中的边数不会超过 (2M) 条,所以每次深度优先搜索在最坏情况下的运行时间与M成正比。整体算下来,时间复杂度就是 (MN) 。这和简单的固定子字符串查找算法在最坏情况下的成本相同,是不是很神奇?

用通俗的话来讲,就好比我们有一本单词书(正则表达式)和一篇文章(文本)。单词书里的单词拼写规则可能很复杂,而文章很长。我们要检查文章里有没有符合单词书里拼写规则的单词,每看文章里的一个字符,都要对照单词书里的各种规则(状态集合),并且在一个由这些规则连接起来的“迷宫”(有向图)里找路,找路的过程就是深度优先搜索。这个“迷宫”的路(边数)最多是单词书长度(M)的两倍,所以找路的时间和单词书长度有关,整体检查完文章的时间就是文章长度(N)和单词书长度(M)的乘积。

二、NFA的构建规则

NFA的构建过程是理解正则表达式匹配的关键,它和我们熟悉的算术表达式求值过程有相似之处,但也有自己的特点。下面我们来详细看看它的构建规则。

(一)连接操作

连接操作在NFA里很好实现。简单来说,状态的匹配转换和字母表中的字符对应起来,这就是连接操作。打个比方,我们有两个字符 “a” 和 “b”,在NFA里,从代表 “a” 的状态到代表 “b” 的状态,通过它们之间的转换关系,就实现了 “a” 和 “b” 的连接。

(二)括号处理

处理括号时,我们把正则表达式里所有左括号的索引压入栈中。遇到右括号时,就把对应的左括号从栈中弹出。这就像我们写数学公式时,括号有配对关系,栈能很好地处理这种嵌套的括号关系。比如在正则表达式 “(a(b|c))” 里,遇到第一个左括号时,把它的索引存到栈里,遇到右括号时,就从栈里取出对应的左括号索引,知道这一对括号的范围。

(三)闭包操作

闭包运算符 “” 有两种情况。如果它出现在单个字符之后,就在这个字符和 “” 之间添加两条相互指向的E-转换;要是出现在右括号之后,就在对应的左括号(栈顶元素)和 “” 之间添加两条相互指向的E-转换。例如,对于 “a”,“a” 和 “” 对应的状态之间就有两条E-转换,这样NFA就能在 “a” 状态和 “” 状态之间来回转换,表示 “a” 可以出现0次或多次。

(四)“或” 表达式处理

在形如 “(A|B)” 的正则表达式中,A和B都是正则表达式。我们要添加两条E-转换,一条从左括号对应的状态指向B中第一个字符对应的状态,另一条从 “|” 字符对应的状态指向右括号对应的状态。同时,把 “|” 运算符和左括号的索引压入栈中,这样到右括号时就能获取所需信息。比如 “(a|b)”,从左括号对应的状态可以通过E-转换到达 “b” 对应的状态,从 “|” 对应的状态可以到达右括号对应的状态,NFA就能在 “a” 和 “b” 之间选择匹配。

下面用表格总结NFA构建规则:

操作类型 规则描述
连接操作 状态的匹配转换与字符对应实现连接
括号处理 左括号索引入栈,右括号弹出对应左括号索引
闭包操作 单个字符后或右括号后,在相应位置添加相互指向的两条E-转换
“或”表达式处理 添加两条E-转换,相关索引压栈辅助处理

三、Java代码实现示例

下面是一个简单的Java代码示例,展示如何构建一个简单正则表达式对应的NFA,并判断文本是否匹配。

import java.util.Stack;

class Digraph {
   
   
    private int V;
    private int[][] adj;

    public Digraph(int v) {
   
   
        V = v;
        adj = new int[v][v];
    }

    public void addEdge(int v, int w) {
   
   
        ad
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一杯年华@编程空间

原创文章不易,盼您慷慨鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值