• 《算法》第五章部分程序 part 6


    ▶ 书中第五章部分程序,包括在加上自己补充的代码,非确定性有穷自动机(NFA),grep 命令(利用 NFA 匹配)

    ● 非确定性有穷自动机(NFA)

     1 package package01;
     2 
     3 import edu.princeton.cs.algs4.StdOut;
     4 import edu.princeton.cs.algs4.Bag;
     5 import edu.princeton.cs.algs4.Stack;
     6 import edu.princeton.cs.algs4.Digraph;
     7 import edu.princeton.cs.algs4.DirectedDFS;
     8 
     9 public class class01
    10 {
    11 
    12     private Digraph graph;     // 含 ε-转移 的有穷自动机图
    13     private String regexp;     // 输入的正则表达式
    14     private final int m;       // 正则表达式包含的字符数
    15 
    16     public class01(String inputRegexp)                             // 根据正则表达式构造 NFA
    17     {
    18         regexp = inputRegexp;
    19         m = regexp.length();
    20         Stack<Integer> ops = new Stack<Integer>();
    21         graph = new Digraph(m + 1);                                 // 自动机的状态数比正则表达式多 1
    22         for (int i = 0; i < m; i++)
    23         {
    24             int lp = i;                                             // 指向当前操作数
    25             if (regexp.charAt(i) == '(' || regexp.charAt(i) == '|') // 遇到 '(' 和 '|',压栈
    26                 ops.push(i);
    27             else if (regexp.charAt(i) == ')')                       // 遇到 ')',吐栈
    28             {
    29                 int or = ops.pop();
    30                 if (regexp.charAt(or ) == '|')                      // 吐出'|',需要添加两条边,设原文为 (A|B)
    31                 {
    32                     lp = ops.pop();                                 // 取出在此之前的 '('
    33                     graph.addEdge(lp, or +1);                       // 第一条边从 '(' 指向 '|' 的后一节点,表示支路 B
    34                     graph.addEdge(or , i);                          // 第二条边从 '|' 指向 ')' 之后,表示支路 A
    35                 }
    36                 else if (regexp.charAt(or ) == '(')                 // 吐出 '(',说明存在一个整体'(...)',用 lp 标记起点,服务于后边的 '*'
    37                     lp = or ;
    38                 else
    39                     assert false;                                   // 栈顶是其他东西(遇不到该分支?因为没有把其他东西压入栈中)
    40             }
    41             if (i < m - 1 && regexp.charAt(i + 1) == '*')           // 下一个字符是闭包,需要添加两条边
    42             {
    43                 graph.addEdge(lp, i + 1);                           // 第一条边从当前节点指向 '*' 节点
    44                 graph.addEdge(i + 1, lp);                           // 第二条边从 '*' 节点指向当前节点,如果当前节点是 ')',则指向当前整体的起点处
    45             }
    46             if (regexp.charAt(i) == '(' || regexp.charAt(i) == '*' || regexp.charAt(i) == ')')  // 如果当前符号是'(*)' 三者之一,则添加添加一条正常边指向下一节点
    47                 graph.addEdge(i, i + 1);
    48         }
    49         if (ops.size() != 0)
    50             throw new IllegalArgumentException("Invalid regular expression");
    51     }
    52 
    53     public boolean recognizes(String txt)               // 使用生成的 NFA 识别输入的字符串
    54     {
    55         Bag<Integer> pc = new Bag<Integer>();           // 存放当前能够到达的所有节点
    56         DirectedDFS dfs = new DirectedDFS(graph, 0);    // 从节点 0 深度优先遍历,表示读取正文第 0 位之前就能通过 ε-转移 到达的所有状态,放入背包 pc 中
    57         for (int v = 0; v < graph.V(); v++)
    58         {
    59             if (dfs.marked(v))
    60                 pc.add(v);
    61         }
    62         for (int i = 0; i < txt.length(); i++)          // 循环每次取原文的一个字符
    63         {
    64             if (txt.charAt(i) == '*' || txt.charAt(i) == '|' || txt.charAt(i) == '(' || txt.charAt(i) == ')')   // 被匹配的原文不能包含 '(*|)'
    65                 throw new IllegalArgumentException("text contains the metacharacter '" + txt.charAt(i) + "'");
    66             Bag<Integer> match = new Bag<Integer>();    // 临时背包,用于存放能与 txt[i] 匹配的所有正则表达式的状态(“状态” 指的是节点编号)
    67             for (int v : pc)                            // 遍历 pc,即以当前能够到达的所有状态为起点尝试匹配 txt[i]
    68             {
    69                 if (v == m)                             // pc 包含节点 m,说明已经到达了终点,完成匹配
    70                     continue;
    71                 if ((regexp.charAt(v) == txt.charAt(i)) || regexp.charAt(v) == '.') // txt[i] 与正则表达式当前的某个状态可以匹配,向 match 中写入 v 的下一节点
    72                     match.add(v + 1);
    73             }
    74             dfs = new DirectedDFS(graph, match);        // 以 match 所有元素为起点深度优先遍历,表示当前所有可达节点通过 ε-转移 到达的所有状态
    75             pc = new Bag<Integer>();                    // 更新 pc
    76             for (int v = 0; v < graph.V(); v++)
    77             {
    78                 if (dfs.marked(v))
    79                     pc.add(v);
    80             }
    81             if (pc.size() == 0)                         // pc 空,说明没有任何可达状态了,停止匹配
    82                 return false;
    83         }
    84         for (int v : pc)                                // 遍历 pc,如果包含节点 m,说明到达了终点,完成匹配
    85         {
    86             if (v == m)
    87                 return true;
    88         }
    89         return false;
    90     }
    91 
    92     public static void main(String[] args)
    93     {
    94         String regexp = "(" + args[0] + ")", txt = args[1]; // 输入的正则表达式最外层用括号包住
    95         class01 nfa = new class01(regexp);
    96         StdOut.println(nfa.recognizes(txt));
    97     }
    98 }

    ● grep 命令实现

     1 package package01;
     2 
     3 import edu.princeton.cs.algs4.StdIn;
     4 import edu.princeton.cs.algs4.StdOut;
     5 import edu.princeton.cs.algs4.NFA;
     6 
     7 public class class01
     8 {
     9     private class01() {}
    10 
    11     public static void main(String[] args)
    12     {
    13         String regexp = "(.*" + args[0] + ".*)";
    14         for (NFA nfa = new NFA(regexp); StdIn.hasNextLine();)
    15         {
    16             String line = StdIn.readLine();
    17             if (nfa.recognizes(line))
    18                 StdOut.println(line);
    19         }
    20     }
    21 }
  • 相关阅读:
    Java通过socket和DTU,RTU连接工业传感器通信
    没有远程桌面授权服务器可以提供许可证 相关,注册表项获得权限方法
    freertos内存pvPortMalloc 和 malloc 区别 ,以及全局变量占用情况
    自学it吧论坛
    安全学习地址
    服务器zfs文件系统修复过程记录
    第1年10月11日 android canvas
    第1年10月9日 swiftui
    第1年9月28日 Android 4.4以后,浏览器内核采用的chromium,可以支持webrtc
    第1年9月19日 ios librtmp
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9869341.html
Copyright © 2020-2023  润新知