Skip to content

Commit af1ae09

Browse files
committed
add nfa
1 parent 30a851f commit af1ae09

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ To test each algorithm(data structure), instead of running the file directly, yo
7878
* [TrieST](algs4/trie_st.go)
7979
* [TST](algs4/tst.go)
8080
* [KMP](algs4/kmp.go)
81+
* [NFA](algs4/nfa.go)
8182

8283

8384
## License

algs4/nfa.go

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package algs4
2+
3+
// NFA ...
4+
type NFA struct {
5+
re string
6+
g *Digraph
7+
m int
8+
}
9+
10+
// NewNFA ...
11+
func NewNFA(re string) *NFA {
12+
m := len(re)
13+
g := NewDigraphV(m + 1)
14+
nfa := &NFA{re, g, m}
15+
ops := NewStack()
16+
for i := 0; i < m; i++ {
17+
lp := i
18+
c := string(re[i])
19+
if c == "(" || c == "|" {
20+
ops.Push(i)
21+
} else if c == ")" {
22+
op := ops.Pop().(int)
23+
if string(re[op]) == "|" {
24+
lp = ops.Pop().(int)
25+
g.AddEdge(lp, op+1)
26+
g.AddEdge(op, i)
27+
} else {
28+
lp = op
29+
}
30+
}
31+
if i < m-1 && string(re[i+1]) == "*" {
32+
g.AddEdge(lp, i+1)
33+
g.AddEdge(i+1, lp)
34+
}
35+
36+
if c == "(" || c == "*" || c == ")" {
37+
g.AddEdge(i, i+1)
38+
}
39+
}
40+
return nfa
41+
}
42+
43+
// Recognizes ...
44+
func (n *NFA) Recognizes(txt string) bool {
45+
pc := NewBag()
46+
dfs := NewDirectedDFS(n.g, 0)
47+
for v := 0; v < n.g.V(); v++ {
48+
if dfs.Marked(v) {
49+
pc.Add(v)
50+
}
51+
}
52+
53+
for i := 0; i < len(txt); i++ {
54+
match := NewBag()
55+
for _, v := range pc.Slice() {
56+
if v.(int) < n.m {
57+
if n.re[v.(int)] == txt[i] || string(n.re[v.(int)]) == "." {
58+
match.Add(v.(int) + 1)
59+
}
60+
}
61+
}
62+
63+
matches := []int{}
64+
for _, m := range match.Slice() {
65+
matches = append(matches, m.(int))
66+
}
67+
pc = NewBag()
68+
dfs = NewDirectedDFSSources(n.g, matches)
69+
for v := 0; v < n.g.V(); v++ {
70+
if dfs.Marked(v) {
71+
pc.Add(v)
72+
}
73+
}
74+
}
75+
76+
for _, v := range pc.Slice() {
77+
if v.(int) == n.m {
78+
return true
79+
}
80+
}
81+
return false
82+
}

cmd/nfa/main.go

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/******************************************************************************
2+
* Execution: go run cmd/nfa/main.go regexp text
3+
*
4+
* % go run cmd/nfa/main.go "(A*B|AC)D" AAAABD
5+
* true
6+
*
7+
* % go run cmd/nfa/main.go "(A*B|AC)D" AAAAC
8+
* false
9+
*
10+
* % go run cmd/nfa/main.go "(a|(bc)*d)*" abcbcd
11+
* true
12+
*
13+
* % go run cmd/nfa/main.go "(a|(bc)*d)*" abcbcbcdaaaabcbcdaaaddd
14+
* true
15+
*
16+
* Remarks
17+
* -----------
18+
* The following features are not supported:
19+
* - The + operator
20+
* - Multiway or
21+
* - Metacharacters in the text
22+
* - Character classes.
23+
*
24+
******************************************************************************/
25+
26+
package main
27+
28+
import (
29+
"fmt"
30+
"os"
31+
32+
"github.com/shellfly/algo/algs4"
33+
)
34+
35+
func main() {
36+
pattern, txt := os.Args[1], os.Args[2]
37+
nfa := algs4.NewNFA(pattern)
38+
fmt.Println(nfa.Recognizes(txt))
39+
}

0 commit comments

Comments
 (0)