Skip to content

Commit 72dd6c1

Browse files
committed
add acyclic and bellman ford sp
1 parent ace6c44 commit 72dd6c1

7 files changed

+242
-10
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ To test each algorithm(data structure), instead of running the file directly, yo
7575
* Shortest Paths
7676
* [EdgeWeightedDigraph](edge_weighted_digraph.go)
7777
* [DijkstraSP](dijkstra_sp.go)
78+
* [AcyclicSP](acyclic_sp.go)
79+
* [BellmanFordSP](bellman_ford_sp.go)
80+
7881

7982
* 5 STRING
8083

acyclic_sp.go

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package algo
2+
3+
// AcyclicSP ...
4+
type AcyclicSP struct {
5+
distTo []float32
6+
edgeTo []*DirectedEdge
7+
}
8+
9+
// NewAcyclicSP ...
10+
func NewAcyclicSP(g *EdgeWeightedDigraph, s int) *AcyclicSP {
11+
edgeTo := make([]*DirectedEdge, g.V())
12+
distTo := make([]float32, g.V())
13+
for v := 0; v < g.V(); v++ {
14+
distTo[v] = PositiveInfinity
15+
}
16+
distTo[s] = 0.0
17+
a := &AcyclicSP{distTo, edgeTo}
18+
top := NewEWDTopological(g)
19+
for _, e := range top.Order() {
20+
a.relax(e)
21+
}
22+
return a
23+
24+
}
25+
26+
func (a *AcyclicSP) relax(e *DirectedEdge) {
27+
v := e.From()
28+
w := e.To()
29+
if a.distTo[w] > a.distTo[v]+e.Weight() {
30+
a.distTo[w] = a.distTo[v] + e.Weight()
31+
a.edgeTo[w] = e
32+
}
33+
}
34+
35+
// DistTo ...
36+
func (a *AcyclicSP) DistTo(v int) float32 {
37+
return a.distTo[v]
38+
}
39+
40+
// HasPathTo ...
41+
func (a *AcyclicSP) HasPathTo(v int) bool {
42+
return a.distTo[v] < PositiveInfinity
43+
}
44+
45+
// PathTo ...
46+
func (a *AcyclicSP) PathTo(v int) (edges []*DirectedEdge) {
47+
if !a.HasPathTo(v) {
48+
return nil
49+
}
50+
51+
for e := a.edgeTo[v]; e != nil; e = a.edgeTo[e.From()] {
52+
// stack
53+
edges = append([]*DirectedEdge{e}, edges...)
54+
}
55+
return
56+
}

bellman_ford_sp.go

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package algo
2+
3+
// BellmanFordSP ...
4+
type BellmanFordSP struct {
5+
distTo []float32
6+
edgeTo []*DirectedEdge
7+
onQ []bool
8+
queue *Queue
9+
cost int
10+
cycle []*DirectedEdge
11+
}
12+
13+
// NewBellmanFordSP ...
14+
func NewBellmanFordSP(g *EdgeWeightedDigraph, s int) *BellmanFordSP {
15+
edgeTo := make([]*DirectedEdge, g.V())
16+
distTo := make([]float32, g.V())
17+
onQ := make([]bool, g.V())
18+
queue := NewQueue()
19+
for v := 0; v < g.V(); v++ {
20+
distTo[v] = PositiveInfinity
21+
}
22+
distTo[s] = 0.0
23+
queue.Enqueue(s)
24+
onQ[s] = true
25+
b := &BellmanFordSP{distTo, edgeTo, onQ, queue, 0, nil}
26+
for !queue.IsEmpty() && !b.hasNegativeCycle() {
27+
v := queue.Dequeue().(int)
28+
b.onQ[v] = false
29+
b.relax(g, v)
30+
}
31+
return b
32+
}
33+
34+
func (b *BellmanFordSP) relax(g *EdgeWeightedDigraph, v int) {
35+
for _, e := range g.Adj(v) {
36+
w := e.To()
37+
if b.distTo[w] > b.distTo[v]+e.Weight() {
38+
b.distTo[w] = b.distTo[v] + e.Weight()
39+
b.edgeTo[w] = e
40+
if !b.onQ[w] {
41+
b.queue.Enqueue(w)
42+
b.onQ[w] = true
43+
}
44+
}
45+
b.cost++
46+
if b.cost%g.V() == 0 {
47+
b.findNegativeCycle()
48+
if b.hasNegativeCycle() {
49+
return // found a negative cycle
50+
}
51+
}
52+
}
53+
}
54+
55+
func (b *BellmanFordSP) findNegativeCycle() {
56+
V := len(b.edgeTo)
57+
spt := NewEdgeWeightedDigraphV(V)
58+
for v := 0; v < V; v++ {
59+
if b.edgeTo[v] != nil {
60+
spt.AddEdge(b.edgeTo[v])
61+
}
62+
}
63+
64+
finder := NewEdgeWeightedDirectedCycle(spt)
65+
b.cycle = finder.Cycle()
66+
}
67+
func (b *BellmanFordSP) hasNegativeCycle() bool {
68+
return b.cycle != nil
69+
}
70+
71+
// DistTo ...
72+
func (b *BellmanFordSP) DistTo(v int) float32 {
73+
return b.distTo[v]
74+
}
75+
76+
// HasPathTo ...
77+
func (b *BellmanFordSP) HasPathTo(v int) bool {
78+
return b.distTo[v] < PositiveInfinity
79+
}
80+
81+
// PathTo ...
82+
func (b *BellmanFordSP) PathTo(v int) (edges []*DirectedEdge) {
83+
if !b.HasPathTo(v) {
84+
return nil
85+
}
86+
87+
for e := b.edgeTo[v]; e != nil; e = b.edgeTo[e.From()] {
88+
// stack
89+
edges = append([]*DirectedEdge{e}, edges...)
90+
}
91+
return
92+
}

cmd/edge-weighted-digraph/main.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88
* Parallel edges and self-loops are permitted.
99
*
1010
* % go run cmd/edge-weighted-digraph/main.go tinyEWD.txt
11-
* 8 vertices, 15 edges
12-
* 0: 6-0 0.58000 0-2 0.26000 0-4 0.38000
13-
* 1: 1-3 0.29000 5-1 0.32000
14-
* 2: 6-2 0.40000 2-7 0.34000 0-2 0.26000
15-
* 3: 3-6 0.52000 1-3 0.29000 7-3 0.39000
16-
* 4: 6-4 0.93000 0-4 0.38000 4-7 0.37000 5-4 0.35000 4-5 0.35000
17-
* 5: 5-1 0.32000 7-5 0.28000 5-7 0.28000 5-4 0.35000 4-5 0.35000
18-
* 6: 6-4 0.93000 6-0 0.58000 3-6 0.52000 6-2 0.40000
19-
* 7: 2-7 0.34000 7-3 0.39000 7-5 0.28000 5-7 0.28000 4-7 0.37000
11+
* 8 vertices, 15 edges
12+
* 0: 0->2 0.26000 0->4 0.38000
13+
* 1: 1->3 0.29000
14+
* 2: 2->7 0.34000
15+
* 3: 3->6 0.52000
16+
* 4: 4->7 0.37000 4->5 0.35000
17+
* 5: 5->1 0.32000 5->7 0.28000 5->4 0.35000
18+
* 6: 6->4 0.93000 6->0 0.58000 6->2 0.40000
19+
* 7: 7->3 0.39000 7->5 0.28000
2020
*
2121
******************************************************************************/
2222

@@ -31,6 +31,6 @@ import (
3131
)
3232

3333
func main() {
34-
graph := algo.NewEdgeWeightedGraph(stdin.NewIn(os.Args[1]))
34+
graph := algo.NewEdgeWeightedDigraph(stdin.NewIn(os.Args[1]))
3535
fmt.Println(graph)
3636
}

digraph.go

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ import (
66
"github.com/shellfly/algo/stdin"
77
)
88

9+
// DigraphInterface ...
10+
type DigraphInterface interface {
11+
V() int
12+
Adj() []*DirectedEdge
13+
}
14+
915
// Digraph ...
1016
type Digraph struct {
1117
v, e int

edge_weighted_directed_cycle.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package algo
2+
3+
// EdgeWeightedDirectedCycle for EdgeWeightedDigrapy
4+
// Note: this is file is just placeholder, see detail algorithm in directed_cycle.go
5+
type EdgeWeightedDirectedCycle struct {
6+
marked []bool
7+
edgeTo []int
8+
cycle []*DirectedEdge
9+
onStack []bool
10+
}
11+
12+
// NewEdgeWeightedDirectedCycle ...
13+
func NewEdgeWeightedDirectedCycle(g *EdgeWeightedDigraph) *EdgeWeightedDirectedCycle {
14+
marked := make([]bool, g.V())
15+
edgeTo := make([]int, g.V())
16+
onStack := make([]bool, g.V())
17+
c := &EdgeWeightedDirectedCycle{marked: marked, edgeTo: edgeTo, onStack: onStack}
18+
if c.hasSelfLoop(g) {
19+
return c
20+
}
21+
if c.hasParallelEdges(g) {
22+
return c
23+
}
24+
25+
for v := 0; v < g.V(); v++ {
26+
if !c.marked[v] {
27+
c.Dfs(g, -1, v)
28+
}
29+
}
30+
return c
31+
}
32+
33+
// hasSelfLoop ...
34+
func (c *EdgeWeightedDirectedCycle) hasSelfLoop(g *EdgeWeightedDigraph) bool {
35+
36+
return false
37+
}
38+
39+
// hasParallelEdges ...
40+
func (c *EdgeWeightedDirectedCycle) hasParallelEdges(g *EdgeWeightedDigraph) bool {
41+
42+
return false
43+
}
44+
45+
// Dfs ...
46+
func (c *EdgeWeightedDirectedCycle) Dfs(g *EdgeWeightedDigraph, u, v int) {
47+
48+
}
49+
50+
// HasCycle ...
51+
func (c *EdgeWeightedDirectedCycle) HasCycle() bool {
52+
return c.cycle != nil
53+
}
54+
55+
// Cycle ...
56+
func (c *EdgeWeightedDirectedCycle) Cycle() []*DirectedEdge {
57+
return c.cycle
58+
}

ewd_topological.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package algo
2+
3+
// EWDTopological implements topological order for a edge weighted digraph
4+
type EWDTopological struct {
5+
order []*DirectedEdge
6+
}
7+
8+
// NewEWDTopological ...
9+
func NewEWDTopological(g *EdgeWeightedDigraph) *EWDTopological {
10+
// See topological.go for detail algorithm
11+
return &EWDTopological{}
12+
}
13+
14+
// Order ...
15+
func (t *EWDTopological) Order() []*DirectedEdge {
16+
return t.order
17+
}

0 commit comments

Comments
 (0)