Skip to content

Commit 0d2c3b0

Browse files
Merge pull request #182 from LYDongD/master
add graph seach algo: BFS & DFS
2 parents 31d0f53 + 9cd780c commit 0d2c3b0

File tree

3 files changed

+322
-0
lines changed

3 files changed

+322
-0
lines changed

go/31_graph/graph_search.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package graph
2+
3+
import (
4+
"container/list"
5+
"fmt"
6+
)
7+
8+
//adjacency table, 无向图
9+
type Graph struct {
10+
adj []*list.List
11+
v int
12+
}
13+
14+
//init graphh according to capacity
15+
func newGraph(v int) *Graph {
16+
graphh := &Graph{}
17+
graphh.v = v
18+
graphh.adj = make([]*list.List, v)
19+
for i := range graphh.adj {
20+
graphh.adj[i] = list.New()
21+
}
22+
return graphh
23+
}
24+
25+
//insert as add edge,一条边存2次
26+
func (self *Graph) addEdge(s int, t int) {
27+
self.adj[s].PushBack(t)
28+
self.adj[t].PushBack(s)
29+
}
30+
31+
//search path by BFS
32+
func (self *Graph) BFS(s int, t int) {
33+
34+
//todo
35+
if s == t {
36+
return
37+
}
38+
39+
//init prev
40+
prev := make([]int, self.v)
41+
for index := range prev {
42+
prev[index] = -1
43+
}
44+
45+
//search by queue
46+
var queue []int
47+
visited := make([]bool, self.v)
48+
queue = append(queue, s)
49+
visited[s] = true
50+
isFound := false
51+
for len(queue) > 0 && !isFound {
52+
top := queue[0]
53+
queue = queue[1:]
54+
linkedlist := self.adj[top]
55+
for e := linkedlist.Front(); e != nil; e = e.Next() {
56+
k := e.Value.(int)
57+
if !visited[k] {
58+
prev[k] = top
59+
if k == t {
60+
isFound = true
61+
break
62+
}
63+
queue = append(queue, k)
64+
visited[k] = true
65+
}
66+
}
67+
}
68+
69+
if isFound {
70+
printPrev(prev, s, t)
71+
} else {
72+
fmt.Printf("no path found from %d to %d\n", s, t)
73+
}
74+
75+
}
76+
77+
//search by DFS
78+
func (self *Graph) DFS(s int, t int) {
79+
80+
prev := make([]int, self.v)
81+
for i := range prev {
82+
prev[i] = -1
83+
}
84+
85+
visited := make([]bool, self.v)
86+
visited[s] = true
87+
88+
isFound := false
89+
self.recurse(s, t, prev, visited, isFound)
90+
91+
printPrev(prev, s, t)
92+
}
93+
94+
//recursivly find path
95+
func (self *Graph) recurse(s int, t int, prev []int, visited []bool, isFound bool) {
96+
97+
if isFound {
98+
return
99+
}
100+
101+
visited[s] = true
102+
103+
if s == t {
104+
isFound = true
105+
return
106+
}
107+
108+
linkedlist := self.adj[s]
109+
for e := linkedlist.Front(); e != nil; e = e.Next() {
110+
k := e.Value.(int)
111+
if !visited[k] {
112+
prev[k] = s
113+
self.recurse(k, t, prev, visited, false)
114+
}
115+
}
116+
117+
}
118+
119+
//print path recursively
120+
func printPrev(prev []int, s int, t int) {
121+
122+
if t == s || prev[t] == -1 {
123+
fmt.Printf("%d ", t)
124+
} else {
125+
printPrev(prev, s, prev[t])
126+
fmt.Printf("%d ", t)
127+
}
128+
129+
}
130+
131+
//func main() {
132+
// graph := newGraph(8)
133+
// graph.addEdge(0, 1)
134+
// graph.addEdge(0, 3)
135+
// graph.addEdge(1, 2)
136+
// graph.addEdge(1, 4)
137+
// graph.addEdge(2, 5)
138+
// graph.addEdge(3, 4)
139+
// graph.addEdge(4, 5)
140+
// graph.addEdge(4, 6)
141+
// graph.addEdge(5, 7)
142+
// graph.addEdge(6, 7)
143+
//
144+
// graph.BFS(0, 7)
145+
// fmt.Println()
146+
// graph.BFS(1, 3)
147+
// fmt.Println()
148+
// graph.DFS(0, 7)
149+
// fmt.Println()
150+
// graph.DFS(1, 3)
151+
// fmt.Println()
152+
//}

go/32_string/string_bf.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
//BF search pattern index, return the first match subs start index
8+
func bfSearch(main string, pattern string) int {
9+
10+
//defensive
11+
if len(main) == 0 || len(pattern) == 0 || len(main) < len(pattern) {
12+
return -1
13+
}
14+
15+
for i := 0; i <= len(main)-len(pattern); i++ {
16+
subStr := main[i : i+len(pattern)]
17+
if subStr == pattern {
18+
return i
19+
}
20+
}
21+
22+
return -1
23+
}
24+
25+
func main() {
26+
27+
main := "abcd227fac"
28+
pattern := "ac"
29+
fmt.Println(bfSearch(main, pattern))
30+
}

go/32_string/string_bm.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"math"
6+
)
7+
8+
//bc: pattern char index hash mapping
9+
func generateBC(pattern string) []int {
10+
11+
bc := make([]int, 256)
12+
13+
for index := range bc {
14+
bc[index] = -1
15+
}
16+
17+
for index, char := range pattern {
18+
bc[int(char)] = index
19+
}
20+
21+
return bc
22+
}
23+
24+
//generate suffix and prefix array for pattern
25+
func generateGS(pattern string) ([]int, []bool) {
26+
m := len(pattern)
27+
suffix := make([]int, m)
28+
prefix := make([]bool, m)
29+
30+
//init
31+
for i := 0; i < m; i++ {
32+
suffix[i] = -1
33+
prefix[i] = false
34+
}
35+
36+
for i := 0; i < m-1; i++ {
37+
j := i
38+
k := 0
39+
for j >= 0 && pattern[j] == pattern[m-1-k] {
40+
j--
41+
k++
42+
suffix[k] = j + 1
43+
}
44+
45+
if j == -1 {
46+
prefix[k] = true
47+
}
48+
}
49+
50+
return suffix, prefix
51+
}
52+
53+
//todo
54+
func moveByGS(patternLength int, badCharStartIndex int, suffix []int, prefix []bool) int {
55+
56+
//length of good suffix
57+
k := patternLength - badCharStartIndex - 1
58+
59+
//complete match
60+
if suffix[k] != -1 {
61+
return badCharStartIndex + 1 - suffix[k]
62+
}
63+
64+
//partial match
65+
for t := patternLength - 1; t > badCharStartIndex+1; t-- {
66+
if prefix[t] {
67+
return t
68+
}
69+
}
70+
71+
//no match
72+
return patternLength
73+
74+
}
75+
76+
func bmSearch(main string, pattern string) int {
77+
//defensive
78+
if len(main) == 0 || len(pattern) == 0 || len(pattern) > len(main) {
79+
return -1
80+
}
81+
82+
bc := generateBC(pattern)
83+
suffix, prefix := generateGS(pattern)
84+
85+
n := len(main)
86+
m := len(pattern)
87+
88+
// i : start index of main string
89+
step := 1
90+
for i := 0; i <= n-m; i = i + step {
91+
subStr := main[i : i+m]
92+
k, j := findBadChar(subStr, pattern, bc)
93+
94+
stepForBC := j - k
95+
//j is bad char occur index
96+
if j == -1 {
97+
return i
98+
}
99+
100+
stepForGS := -1
101+
if j < m-1 {
102+
stepForGS = moveByGS(m, j, suffix, prefix)
103+
}
104+
105+
//k is bad char index in pattern
106+
step = int(math.Max(float64(stepForBC), float64(stepForGS)))
107+
}
108+
109+
return -1
110+
}
111+
112+
func findBadChar(subStr string, pattern string, bc []int) (int, int) {
113+
114+
j := -1
115+
k := -1
116+
badChar := rune(0)
117+
118+
for index := len(subStr) - 1; index >= 0; index-- {
119+
if subStr[index] != pattern[index] {
120+
j = index
121+
badChar = rune(subStr[index])
122+
break
123+
}
124+
}
125+
126+
//if bad character exist, then find it's index at pattern
127+
if j > 0 {
128+
k = bc[int(badChar)]
129+
}
130+
131+
return k, j
132+
}
133+
134+
func main() {
135+
136+
main := "abcacabcbcabcabc"
137+
pattern := "cabcab"
138+
139+
fmt.Println(bmSearch(main, pattern))
140+
}

0 commit comments

Comments
 (0)