forked from shellfly/algo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cycle.go
99 lines (89 loc) · 1.61 KB
/
cycle.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package algs4
// Cycle ...
type Cycle struct {
marked []bool
edgeTo []int
cycle *Stack
}
// NewCycle ...
func NewCycle(g *Graph) *Cycle {
marked := make([]bool, g.V())
edgeTo := make([]int, g.V())
c := &Cycle{marked: marked, edgeTo: edgeTo}
if c.hasSelfLoop(g) {
return c
}
if c.hasParallelEdges(g) {
return c
}
for v := 0; v < g.V(); v++ {
if !c.marked[v] {
c.Dfs(g, -1, v)
}
}
return c
}
// hasSelfLoop ...
func (c *Cycle) hasSelfLoop(g *Graph) bool {
for v := 0; v < g.V(); v++ {
for _, w := range g.Adj(v) {
if v == w {
c.cycle = NewStack()
c.cycle.Push(v)
c.cycle.Push(w)
return true
}
}
}
return false
}
// hasParallelEdges ...
func (c *Cycle) hasParallelEdges(g *Graph) bool {
c.marked = make([]bool, g.V())
for v := 0; v < g.V(); v++ {
for _, w := range g.Adj(v) {
if c.marked[w] {
c.cycle = NewStack()
c.cycle.Push(v)
c.cycle.Push(w)
c.cycle.Push(v)
return true
}
c.marked[w] = true
}
// reset so marked[v] = false for all v
for _, w := range g.Adj(v) {
c.marked[w] = false
}
}
return false
}
// Dfs ...
func (c *Cycle) Dfs(g *Graph, u, v int) {
c.marked[v] = true
for _, w := range g.Adj(v) {
// short circuit if cycle already found
if c.cycle != nil {
return
}
if !c.marked[w] {
c.edgeTo[w] = v
c.Dfs(g, v, w)
} else if w != u {
c.cycle = NewStack()
for x := v; x != w; x = c.edgeTo[x] {
c.cycle.Push(x)
}
c.cycle.Push(w)
c.cycle.Push(v)
}
}
}
// HasCycle ...
func (c *Cycle) HasCycle() bool {
return c.cycle != nil
}
// Cycle ...
func (c *Cycle) Cycle() *Stack {
return c.cycle
}