Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9655ce9

Browse files
author
zhengwei.hzw
committed
增加 NFA 算法
1 parent 54789ac commit 9655ce9

File tree

4 files changed

+105
-3
lines changed

4 files changed

+105
-3
lines changed

src/Digraph/directedDFS.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ class DirectedDFS {
1616
}
1717

1818
_dfs(G, v) {
19-
if(!G.isV(v))
20-
throw new Error('别犯傻, 这个顶点都不存在')
21-
2219
this._marked.push(v)
2320

2421
~~(G.adj(v) || []).forEach(w => {

src/Digraph/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class Digraph {
55
this._E = 0
66
this._V = []
77
// 如果用对象的形式没法区分以 '1' 和 1 做 key
8+
// ES6 new Set
89
this._adjK = []
910
this._adjV = []
1011
}

src/NFA/index.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
'use strict'
2+
3+
const Digraph = require('../Digraph/index')
4+
const DirectedDFS = require('../Digraph/directedDFS')
5+
6+
class NFA {
7+
8+
constructor(regexp) {
9+
10+
let ops = []
11+
const M = this.__M = regexp.length
12+
, G = this.__G = new Digraph() // epsilon 转换
13+
14+
15+
this.__G.addEdge(M, M + 1)
16+
17+
this.__re = regexp
18+
19+
for (let i = 0; i < M; i++) {
20+
let lp = i
21+
22+
if (regexp[i] === '(' || regexp[i] === '|') {
23+
ops.push(i)
24+
} else if (regexp[i] === ')') {
25+
let or = ops.pop()
26+
if (regexp[or] === '|') {
27+
lp = ops.pop()
28+
G.addEdge(lp, or + 1)
29+
G.addEdge(or, i)
30+
} else {
31+
lp = or
32+
}
33+
}
34+
35+
// 查看 '*' 字符
36+
if (i < M - 1 && regexp[i + 1] === '*') {
37+
G.addEdge(lp, i + 1)
38+
G.addEdge(i + 1, lp)
39+
}
40+
41+
if (regexp[i] === '(' || regexp[i] === '*' || regexp[i] === ')') {
42+
G.addEdge(i, i + 1)
43+
}
44+
45+
}
46+
47+
}
48+
49+
recognizes(txt) {
50+
51+
let pc = [],
52+
G = this.__G,
53+
M = this.__M,
54+
re = this.__re,
55+
dfs = new DirectedDFS(G, 0)
56+
57+
58+
for (let v = 0; v < G.V(); v++) {
59+
if (dfs.marked(v)) pc.push(v)
60+
}
61+
62+
for (let i = 0; i < txt.length; i++) {
63+
let match = []
64+
for (let j = 0; j < pc.length; j++) {
65+
if (pc[j] < M) {
66+
if (re[pc[j]] === txt[i] || re[pc[j]] === '.') {
67+
match.push(pc[j] + 1)
68+
}
69+
}
70+
}
71+
72+
pc = []
73+
dfs = new DirectedDFS(G, match)
74+
75+
for (let v = 0; v < G.V(); v++) {
76+
if (dfs.marked(v)) {
77+
pc.push(v)
78+
}
79+
}
80+
81+
}
82+
83+
return pc.includes(M)
84+
}
85+
86+
87+
}
88+
89+
90+
module.exports = NFA
91+

src/NFA/test-case.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
'use strict'
2+
3+
const NFA = require('./index')
4+
5+
6+
let data = ['AC', 'AD', 'AAA', 'ABD', 'ACD', 'BCD', 'AAABD','ABCCBD', 'BABAAA', 'BABBAAA']
7+
, nfa = new NFA('(A*B|AC)D')
8+
9+
10+
data.forEach(v => {
11+
console.log(v + ': ' + nfa.recognizes(v))
12+
})
13+

0 commit comments

Comments
 (0)