-
Notifications
You must be signed in to change notification settings - Fork 121
/
eulerCircuit.go
78 lines (69 loc) · 1.76 KB
/
eulerCircuit.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
package graph
type vertexDegree struct {
iDegree, oDegree int
}
func (e *vertexDegree) init(vertex interface{}) *vertexDegree {
e.iDegree = 0
e.oDegree = 0
return e
}
func newEulerVertex(vertex interface{}) *vertexDegree {
return new(vertexDegree).init(vertex)
}
func checkDegree(degree *vertexDegree, e *dfsElement) bool {
if degree.iDegree == 0 || degree.oDegree == 0 {
return false
}
if e.Iter.Len() == 1 && e.Iter.Value() == e.V {
//check single vertex loop
return false
}
return degree.iDegree == degree.oDegree
}
func checkVertexAndEdgeCnt(vCnt, eCnt int) bool {
return eCnt == vCnt+1
}
func eulerCircuit(g graph) []edge {
degrees := make(map[interface{}]*vertexDegree)
path := make([]edge, 0, 0)
vCnt, eCnt := 0, 0
nonTreeEdgeHandler := func(start, end *dfsElement) {
if start.P != nil && start.P != end {
degrees[start.V].oDegree++
degrees[end.V].iDegree++
eCnt++
path = append(path, edge{start.V, end.V})
}
}
handler := newDFSVisitHandler()
handler.BeforeDfsHandler = func(v *dfsElement) {
degrees[v.V] = newEulerVertex(v.V)
}
handler.TreeEdgeHandler = func(start, end *dfsElement) {
eCnt++
degrees[start.V].oDegree++
degrees[end.V].iDegree = 1
path = append(path, edge{start.V, end.V})
}
handler.BackEdgeHandler = nonTreeEdgeHandler
//dfs O(E)
for _, v := range g.AllVertices() {
vCnt++
if !handler.Elements.exist(v) {
dfsVisit(g, v, handler)
}
}
//for single vertex condition
if !checkVertexAndEdgeCnt(vCnt, eCnt) {
return nil
}
//check and output path, O(E)
for _, e := range path {
if !checkDegree(degrees[e.Start], handler.Elements.get(e.Start).(*dfsElement)) ||
!checkDegree(degrees[e.End], handler.Elements.get(e.End).(*dfsElement)) {
//check degree rules
return nil
}
}
return path
}