NFA转DFA及最优化

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/y3over/article/details/100882180

      《正则表达式转NFA》NFA是捏着正则式去比文本,吃掉一个字符,就把它跟正则式比较,匹配就记下来:“某年某月某日在某处匹配上了!”,然后接着往下干。一旦不匹配,就把刚吃的这个字符吐出来,一个个的吐,直到回到上一次匹配的地方。

而DFA捏着文本串去比较正则式,看到一个子正则式,就把可能的匹配串全标注出来,然后再看正则式的下一个部分,根据新的匹配结果更新标注。

 

例如用正则式/perl|perlman/来匹配文本 ‘perlman book’。如果是NFA,则以正则式为导向,手里捏着正则式,眼睛看着文本,一个字符一个字符的吃,吃完 ‘perl’ 以后,跟第一个子正则式/perl/已经匹配上了,于是记录在案,往下再看,吃进一个 ‘m’,这下糟了,跟子式/perl/不匹配了,于是把m吐出来,向上汇报说成功匹配 ‘perl’,不再关心其他,也不尝试后面那个子正则式/perlman/,自然也就看不到那个更好的答案了。

如果是DFA,它是以文本为导向,手里捏着文本,眼睛看着正则式,一口一口的吃。吃到/p/,就在手里的 ‘p’ 上打一个钩,记上一笔,说这个字符已经匹配上了,然后往下吃。当看到 /perl/ 之后,DFA不会停,会尝试再吃一口。这时候,第一个子正则式已经山穷水尽了,没得吃了,于是就甩掉它,去吃第二个子正则式的/m/。这一吃好了,因为又匹配上了,于是接着往下吃。直到把正则式吃完,心满意足往上报告说成功匹配了 ‘perlman’。

 

确定型有穷自动机

确定型有穷自动机是不确定有穷自动机中的一个特例,其中:

  1. 没有输出ε之上的转换动作。
  2. 对每个状态s和每个输入符号a,有且只有一条标号为a的边离开s

确定型有穷自动机的转换

  • ε-closure的操作就是去ε
  • move的操作就是对路径的归并

  1. Dstates保存着新节点[初始化是ε-closure(s0)]状态
  2. 发现Dstates还有末被标记的节点进入循环并打上标记
  3. 对新节点T(T=ε-closure(s))集合进行移边操作和去ε得到新集合U
  4. 如果发现U没在Dstates中,加入并不打标记
  5. 创建一条新边Dtran[T,a]

求出ε-closure(s0)]={0,1,3,4,5,6,7,9}并创建表格

IIaIb
{0,1,3,4,5,6,7,9}  

对基移a,b操作

移a或b集合操作的时候得到的新集合如果不第一列中,则新开一列标记上,并再对新集合移a或b.如此循环 。

新的终态的判断方法就是包含原来终态的集合就为终态,例如此题原来终态为9,所以包含9的集合就为终态,[双圈代表终态]
新的初态就是包含原来初态的集合就为初态,例如此题原来初态为0,所以包含0的集合就为初态

 

将DFA最小化

对于同一个语言,可以存在多个识别此语言的DFA,所以,求出DFA后,通常我们还需要对DFA进行简化操作,求出最简DFA。
简化的本质是合并性质相同的状态,以减少整个图的大小。

 

无关状态

(1)多于状态:对于一个状态Si,若从开始状态出发,不可能到达该状态Si,则Si为多余(无用)状态。
(2)死状态:对于一个状态Si,对于任意输入符号a,若转到它本身后,不可能从它到达终止状态,则称Si为死状态。

等价状态:若Si为自动机的一个状态,我们把从s出发能导出的所有符号串的集合记为L(s)。设有两个状态s和t,若有L(s)=L(t),则称s和t是等价状态。
(1) 一致性条件:状态s和t必须同时为终态或非终态
(2) 蔓延性条件:对于所有输入符号,状态s和状态t必须转化到等价的状态

 

DFA的化简算法:对于DFA M=(S,Σ,f,S0,Z)

(1)首先将DFA的状态集进行初始化,分成Π=(Z,S-Z); S为全部状态,Z为终态。
(2) 用下面的过程对Π构造新的划分Π 


 
 
  1. for (Π中每个组G) {
  2. 把G划分成小组,G中的任意两个状态Si和Sj在同一组中,
  3. 当且仅当对于Σ中任意输入符号a ,Si和Sj的a转换是到同一组中,move(Si,a) ∈Gi ,move(Sj,a) ∈Gi。
  4. 只要Si和Sj的a转换是到不同的组中,则说明Si和Sj是可区别的,可进行划分。在Π new中用刚完成的对G的划分代替原来的G。
  5. }

(3)重复执行(2),直到Π中每个状态集不能再划分(Π new= Π)为止;
(4)合并等价状态 ,在每个G中,取任意状态作为代表,删去其它状态;
(5)删去无关状态,从其它状态到无关状态的转换都成为无定义。
 

①首次划分: Π0=({2,3,4,5},{0,1})
②在G={2,3,4,5}中:f(2,a)=1,f(4,a)=0(转向终态集{0,1});f(3,a)=3,f(5,a)=5(转向非终态集{2,3,4,5}),故{2,4}和{3,5}是可区别的,得Π1=({2,4},{3,5},{0,1});
③在G={2,4}中,f(2,a)=1,f(4,a)=0(转向终态子集),而f(2,b)=3,f(4,b)=5(转向非终态子集{3,5}),所以不可区别,不再进行划分;
④考察G={3,5},f(3,a)=3,f(5,a)=5(转向非终态子集{3,5}),f(3,b)=2,f(5,b)=4(转向非终态子集{2,4}), 所以不可区别,不再进行划分;
⑤考察G={0,1},f(0,a)=f(1,a)=1(转向终态集{0,1}); f(0,b)=2f,(1,b)=4(转向非终态子集{2,4}),所以不可区别,不再进行划分;
⑦进一步进行考察,可以发现每个子集都不能再划分了;
⑧消去等价状态:{0,1}用0表示,{2,4}用2表示,{3,5}用3表示,如右图所示
⑨去掉无关状态,因DFA M’中没有无关状态,所以下图即为最后结果。

 

JAVA代码


 
 
  1. package com.moyao.magic;
  2. import com.moyao.magic.SuffixAlgorithm.Operator;
  3. import java.util.*;
  4. import java.util.stream.Collectors;
  5. public class NfaAlgorithm {
  6. private static String prepareString(String _regex) {
  7. String regex = "";
  8. char[] regexs = _regex.replaceAll( " ", "").toCharArray();
  9. for ( int i = 0; i < regexs.length; i++) {
  10. if (i == 0)
  11. regex += regexs[i];
  12. else {
  13. if (regexs[i] == '|' || regexs[i] == '*' || regexs[i] == ')') {
  14. regex += regexs[i];
  15. } else {
  16. if (regexs[i - 1] == '(' || regexs[i - 1] == '|')
  17. regex += regexs[i];
  18. else
  19. regex += ( "&" + regexs[i]);
  20. }
  21. }
  22. }
  23. return regex;
  24. }
  25. private static String E = "epsllon";
  26. public static Graph transformNFA(String suffixRegex){
  27. char[] rs = suffixRegex.toCharArray();
  28. Stack<Object> operandStack = new Stack();
  29. for ( int i = 0; i<rs.length; i++){
  30. char o = rs[i];
  31. if(!Operator.isOperator(o)){
  32. operandStack.push(String.valueOf(o));
  33. } else{
  34. Operator operator = Operator.findOperator(o);
  35. Graph graph = null;
  36. switch ( operator){
  37. case ADD: //'&'
  38. Object av1 = operandStack.pop();
  39. Object av2 = operandStack.pop();
  40. graph = Graph.parse(av2);
  41. graph. add(av1);
  42. break;
  43. case MULTIPLY: //'*'
  44. Object mv = operandStack.pop();
  45. graph = Graph.parse(mv);
  46. graph.multiply();
  47. break;
  48. case DIVIDE: //'|'
  49. Object dv1 = operandStack.pop();
  50. Object dv2 = operandStack.pop();
  51. graph = Graph.parse(dv2);
  52. graph.divide(dv1);
  53. break;
  54. }
  55. operandStack.push(graph);
  56. }
  57. }
  58. return Graph.parse(operandStack.pop());
  59. }
  60. public static Graph transformDFA(Graph nfa){
  61. List<String> lbs = nfa.getLabels();
  62. List<UNode> us = new ArrayList<>();
  63. List<UNode> doList = new ArrayList<>();
  64. List<Edge> edges = new ArrayList<>();
  65. UNode s = new UNode(nfa.closure(nfa.start));
  66. UNode e = null;
  67. doList. add(s);
  68. us. add(s);
  69. while(!doList.isEmpty()){
  70. UNode u = doList. remove( 0);
  71. for (String lb : lbs){
  72. List<Node> nodes = nfa.closure(nfa.move(u.getNodes(),lb));
  73. if(nodes.isEmpty()) continue;
  74. UNode next = new UNode(nodes);
  75. int index = us.indexOf(next);
  76. if(index >= 0){
  77. next = us. get(index);
  78. }
  79. Edge edge = new Edge(u,next,lb);
  80. edges. add(edge);
  81. if(index >= 0) continue;
  82. doList. add(next);
  83. us. add(next);
  84. if(e != null) continue;
  85. e = next.nodes
  86. .stream()
  87. .anyMatch(node -> { return node == nfa.end;}) ?
  88. next : null;
  89. }
  90. }
  91. return new Graph(edges,s, e);
  92. }
  93. public static Graph optimizeDFA(Graph dfa){
  94. List<String> lbs = dfa.getLabels();
  95. int pos = 1;
  96. int end = 2;
  97. Map<Integer, Node> nodeMap = dfa.getNodes();
  98. Map<Integer,Integer> groupMap = new HashMap<>();
  99. nodeMap.values().forEach(n->{
  100. groupMap.put(n.id, n == dfa.end ? 0 : 1);
  101. });
  102. while (pos < end){
  103. final int searchIndex = pos;
  104. List<Node> nodes = groupMap.entrySet().stream()
  105. .filter(e-> e.getValue() == searchIndex).map(e->{ return nodeMap. get(e.getKey());})
  106. .collect(Collectors.toList());
  107. boolean success = true;
  108. for (String lb:lbs) {
  109. Map<Integer,List<Integer>> resultMap = new HashMap<>();
  110. for (Node node: nodes) {
  111. Node n = dfa.move(node,lb);
  112. int groupResult = n == null ? -1 : groupMap. get(node.id);
  113. List<Integer> ll = resultMap. get( -1);
  114. if (ll == null){
  115. ll = new ArrayList<>();
  116. ll. add(node.id);
  117. }
  118. resultMap.put(groupResult,ll);
  119. }
  120. int count = resultMap.keySet().size();
  121. if(count == 1)
  122. continue;
  123. int b = pos;
  124. Iterator<List<Integer>> it = resultMap.values().iterator();
  125. while (it.hasNext()){
  126. List<Integer> idList = it.next();
  127. for (Integer id:idList) {
  128. groupMap.put(id,b++);
  129. }
  130. }
  131. end = b;
  132. success = false;
  133. break;
  134. }
  135. if(success) pos++;
  136. }
  137. Map<Integer, Node> newNodeMap = new HashMap<>();
  138. Node s = new Node(groupMap. get(dfa.start.id));
  139. Node e = new Node(groupMap. get(dfa.end.id));
  140. newNodeMap.put(s.id, s);
  141. newNodeMap.put(e.id, e);
  142. List<Edge> edges = dfa.edges.stream().map(edge->{
  143. Node nodeBegin = newNodeMap.getOrDefault(edge.begin.id, new Node(groupMap. get(edge.begin.id)));
  144. Node nodeEnd = newNodeMap.getOrDefault(edge.end.id, new Node(groupMap. get(edge.end.id)));
  145. return new Edge(nodeBegin,nodeEnd,edge.label);
  146. }).distinct().collect(Collectors.toList());
  147. return new Graph(edges,s, e);
  148. }
  149. public static void main(String[] args) {
  150. String exp = prepareString( "(A*B|AC)D");
  151. //String exp = prepareString("AB");
  152. System. out.println(exp);
  153. String regex = SuffixAlgorithm.rpn(exp);
  154. System. out.println(regex);
  155. Graph fna = transformNFA(regex);
  156. System. out.println(fna);
  157. Graph dfa = transformDFA(fna);
  158. System. out.println(dfa);
  159. Graph opDfa = optimizeDFA(dfa);
  160. System. out.println(opDfa);
  161. }
  162. static class Graph {
  163. private List<Edge> edges;
  164. private Node start;
  165. private Node end;
  166. public Graph(List<Edge> edges, Node start, Node end) {
  167. this.edges = edges;
  168. this.start = start;
  169. this.end = end;
  170. }
  171. private Graph(String label){
  172. this.start = new Node();
  173. this.end = new Node();
  174. this.edges = new ArrayList<>();
  175. Edge edge = new Edge(start,end,label);
  176. this.edges. add(edge);
  177. }
  178. public static Graph parse(Object obj){
  179. if(obj instanceof Graph){
  180. return (Graph) obj;
  181. }
  182. if(obj instanceof String)
  183. return new Graph((String)obj);
  184. throw new IllegalArgumentException( "not support class["+obj.getClass()+ "]");
  185. }
  186. public void add(Object obj){
  187. if(obj instanceof String){
  188. add((String)obj);
  189. return;
  190. }
  191. if(obj instanceof Graph) {
  192. add((Graph) obj);
  193. return;
  194. }
  195. throw new IllegalArgumentException( "not support class["+obj.getClass()+ "]");
  196. }
  197. public void divide(Object obj){
  198. if(obj instanceof String){
  199. divide(parse(obj));
  200. return;
  201. }
  202. if(obj instanceof Graph) {
  203. divide((Graph) obj);
  204. return;
  205. }
  206. throw new IllegalArgumentException( "not support class["+obj.getClass()+ "]");
  207. }
  208. public void multiply(){
  209. Node nodeStart = this.start;
  210. Node nodeEnd = this.end;
  211. this.start = new Node();
  212. this.end = new Node();
  213. Edge edge1 = new Edge(nodeEnd,nodeStart,E);
  214. Edge edge2 = new Edge( this.start,nodeStart,E);
  215. Edge edge3 = new Edge(nodeEnd, this.end,E);
  216. Edge edge4 = new Edge( this.start, this.end,E);
  217. this.edges. add(edge1);
  218. this.edges. add(edge2);
  219. this.edges. add(edge3);
  220. this.edges. add(edge4);
  221. }
  222. private void divide(Graph graph){
  223. Node nodeStart = this.start;
  224. Node nodeEnd = this.end;
  225. this.start = new Node();
  226. this.end = new Node();
  227. Edge edge1 = new Edge( this.start,graph.start,E);
  228. Edge edge2 = new Edge( this.start,nodeStart,E);
  229. Edge edge3 = new Edge(nodeEnd, this.end,E);
  230. Edge edge4 = new Edge(graph.end, this.end,E);
  231. this.edges. add(edge1);
  232. this.edges. add(edge2);
  233. this.edges. add(edge3);
  234. this.edges. add(edge4);
  235. this.edges.addAll(graph.edges);
  236. }
  237. private void add(String label){
  238. Node mid = end;
  239. this.end = new Node();
  240. Edge edge = new Edge(mid,end,label);
  241. this.edges. add(edge);
  242. }
  243. private void add(Graph graph){
  244. Node node = this.end;
  245. this.end = graph.end;
  246. edges.stream().filter(edge -> edge.end == node)
  247. .forEach(edge -> {
  248. edge.end = graph.start;
  249. });
  250. this.edges.addAll(graph.edges);
  251. }
  252. public List<Node> closure(Node s){
  253. return closure(Arrays.asList(s));
  254. }
  255. public List<Node> closure(List<Node> u){
  256. List<Node> result = new ArrayList<>();
  257. do{
  258. result.addAll(u);
  259. u = move(u,E);
  260. } while (!u.isEmpty());
  261. return result;
  262. }
  263. public Node move(Node t, String lable){
  264. List<Node> result = move(Arrays.asList(t), lable);
  265. if(result.isEmpty()) return null;
  266. return result. get( 0);
  267. }
  268. public List<Node> move(List<Node> t, String lable){
  269. return edges.stream()
  270. .filter(edge -> {
  271. if(!edge.label. equals(lable))
  272. return false;
  273. for (Node n : t){
  274. if(edge.begin == n)
  275. return true;
  276. }
  277. return false;
  278. })
  279. .map(edge -> { return edge.end;})
  280. .collect(Collectors.toList());
  281. }
  282. public List<String> getLabels(){
  283. return edges.stream()
  284. .filter(edge -> { return !edge.label. equals(E);})
  285. .map(edge -> { return edge.label;})
  286. .distinct()
  287. .collect(Collectors.toList());
  288. }
  289. public Map<Integer,Node> getNodes(){
  290. Map<Integer, Node> map = new HashMap<>();
  291. edges.forEach(edge -> {
  292. map.put(edge.begin.id, edge.begin);
  293. map.put(edge.end.id, edge.end);
  294. });
  295. return map;
  296. }
  297. @ Override
  298. public String toString( ) {
  299. String printString = "Start=" + this.start + " End=" + this.end + "\n";
  300. for ( int i = 0; i < edges.size(); i++) {
  301. printString += edges. get(i) + "\n";
  302. }
  303. return printString;
  304. }
  305. }
  306. //边
  307. static class Edge {
  308. private Node begin;
  309. private Node end;
  310. private String label;
  311. public Edge(Node begin, Node end, String label) {
  312. this.begin = begin;
  313. this.end = end;
  314. this.label = label;
  315. }
  316. @ Override
  317. public boolean equals( Object o) {
  318. if ( this == o) return true;
  319. if (o == null || getClass() != o.getClass()) return false;
  320. Edge edge = (Edge) o;
  321. if (!begin. equals(edge.begin)) return false;
  322. if (!end. equals(edge.end)) return false;
  323. return label. equals(edge.label);
  324. }
  325. @ Override
  326. public int hashCode( ) {
  327. int result = begin.hashCode();
  328. result = 31 * result + end.hashCode();
  329. result = 31 * result + label.hashCode();
  330. return result;
  331. }
  332. @ Override
  333. public String toString( ) {
  334. return "Edge [begin=" + begin + ", end=" + end + ", label=" + label+ "]";
  335. }
  336. }
  337. //节点
  338. static class UNode extends Node {
  339. private List<Node> nodes;
  340. public UNode(List<Node> nodes) {
  341. this.nodes = nodes;
  342. }
  343. public List<Node> getNodes() {
  344. return nodes;
  345. }
  346. @ Override
  347. public boolean equals( Object obj) {
  348. if(!(obj instanceof UNode)) return super. equals(obj);
  349. UNode b = (UNode)obj;
  350. if(nodes.size() != b.nodes.size()) return false;
  351. List<Node> desc = new ArrayList<>(Arrays.asList( new UNode[nodes.size()]));
  352. Collections.copy(desc, nodes);
  353. desc.removeAll(b.nodes);
  354. if(desc.isEmpty()) return true;
  355. return false;
  356. }
  357. }
  358. //节点
  359. static class Node {
  360. private int id;
  361. private static int ID= 0;
  362. public Node(int id){ this.id = id;}
  363. public Node(){
  364. this.id=ID++;
  365. }
  366. @ Override
  367. public boolean equals( Object obj) {
  368. if(!(obj instanceof Node))
  369. return super. equals(obj);
  370. Node b = (Node)obj;
  371. return id == b.id;
  372. }
  373. @ Override
  374. public String toString( ) {
  375. return id+ "";
  376. }
  377. }
  378. }

                            · 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值