Skip to content

Commit 7be0942

Browse files
committed
Merge branch 'feature/topologicalsort' into develop
2 parents b8a160a + e503bc4 commit 7be0942

File tree

8 files changed

+143
-8
lines changed

8 files changed

+143
-8
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ General purpose data structures and algorithms.
3535
- [ ] Graph
3636
- [ ] Directed Matrix Graph
3737
- [ ] Undirected Matrix Graph
38-
- [ ] Directed Adjacency Graph
39-
- [ ] Undirected Adjacency Graph
38+
- [x] Directed Adjacency Graph
39+
- [x] Undirected Adjacency Graph
4040
- [ ] Directed Edged Graph
4141
- [ ] Undirected Edged Graph
4242
- [ ] Flow Capacity Graph
@@ -69,7 +69,7 @@ General purpose data structures and algorithms.
6969
- [ ] Cyclic Components
7070
- [ ] Euler Tour
7171
- Visit each edge once
72-
- [ ] Topological Sort
72+
- [x] Topological Sort
7373
- [ ] Graph Minimum Spanning Tree
7474
- [ ] Lazy Prim's Minimum Spanning Tree
7575
- [ ] Eager Prim's Minimum Spanning Tree

src/bguiz/struct/graph/BreadthFirstSearchGraph.hx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package bguiz.struct.graph;
33
import bguiz.struct.dict.ArrayDictionary;
44
using bguiz.struct.dict.ArrayQueue;
55

6+
@:expose("Struct.BreadthFirstSearchGraph")
67
class BreadthFirstSearchGraph {
78
public static function breadthFirstSearch<T> (
89
graph: AdjacencyGraph<T>,

src/bguiz/struct/graph/ConnectedSearchGraphResult.hx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ package bguiz.struct.graph;
22

33
typedef ConnectedSearchGraphResult<T> = {
44
> SearchGraphResult<T>,
5-
var connected:Array<Int>;
5+
var connected:Array<Null<Int>>;
66
var groupCount:Int;
77
}

src/bguiz/struct/graph/DepthFirstSearchGraph.hx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ package bguiz.struct.graph;
33
import bguiz.struct.dict.ArrayDictionary;
44
using bguiz.struct.dict.ArrayStack;
55

6+
@:expose("Struct.DepthFirstSearchGraph")
67
class DepthFirstSearchGraph {
78
public static function depthFirstSearch<T> (
89
graph: AdjacencyGraph<T>,
9-
startVertex:Int): SearchGraphResult<T> {
10+
startVertex: Int
11+
): SearchGraphResult<T> {
1012
var result = {
1113
startVertex: startVertex,
1214
edgeTo: [for (i in 0...graph.vertices.length) null],
@@ -17,8 +19,9 @@ class DepthFirstSearchGraph {
1719
}
1820

1921
public static function depthFirstSearchPart<T> (
20-
graph:AdjacencyGraph<T>,
21-
startVertex:Int, result:SearchGraphResult<T>
22+
graph: AdjacencyGraph<T>,
23+
startVertex: Int,
24+
result: SearchGraphResult<T>
2225
): Void {
2326
// recursion in a typical DFS implementation is so simple here
2427
// that a stack-based implementation is very simple

src/bguiz/struct/graph/SearchGraphResult.hx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ package bguiz.struct.graph;
22

33
typedef SearchGraphResult<T> = {
44
var startVertex:Int;
5-
var edgeTo:Array<Int>;
5+
var edgeTo:Array<Null<Int>>;
66
var marked:Array<Bool>;
77
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package bguiz.struct.graph;
2+
3+
import bguiz.struct.dict.ArrayDictionary;
4+
using bguiz.struct.dict.ArrayStack;
5+
6+
//NOTE *must* be a directed acyclic graph (DAG) i.e. no cycles
7+
@:expose("Struct.TopologicalSortGraph")
8+
class TopologicalSortGraph {
9+
10+
// Find an order of all the vetrices such that the all of
11+
// the directed edges point in the same direction
12+
// Perform a depth first search, and then returnthe vertices in reverse post order
13+
// Every vertex must be searched, hence no start vertex needs to be specified
14+
public static function topologicalSort<T> (
15+
graph: AdjacencyGraph<T>
16+
): TopologicalSortGraphResult<T> {
17+
var result = {
18+
reversePostOrderVertices: [],
19+
marked: [for (i in 0...graph.vertices.length) false]
20+
};
21+
for (i in 0...graph.vertices.length) {
22+
if (!result.marked[i]) {
23+
topologicalSortPart(graph, i, result);
24+
}
25+
}
26+
return result;
27+
}
28+
29+
public static function topologicalSortPart<T> (
30+
graph: AdjacencyGraph<T>,
31+
fromVertex: Int,
32+
result: TopologicalSortGraphResult<T>
33+
) : Void {
34+
//TODO find a way to do this iteratively (rather than recursively)
35+
// however tracking reverse post order of the depth first search
36+
// proves to be tricky to implement
37+
result.marked[fromVertex] = true;
38+
for (toVertex in graph.adjacents[fromVertex]) {
39+
if (!result.marked[toVertex]) {
40+
topologicalSortPart(graph, toVertex, result);
41+
}
42+
}
43+
result.reversePostOrderVertices.push(fromVertex);
44+
}
45+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package bguiz.struct.graph;
2+
3+
typedef TopologicalSortGraphResult<T> = {
4+
var marked:Array<Bool>;
5+
var reversePostOrderVertices:Array<Int>;
6+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package bguiz.struct.test.graph;
2+
3+
import massive.munit.util.Timer;
4+
import massive.munit.Assert;
5+
import massive.munit.async.AsyncFactory;
6+
7+
import bguiz.struct.graph.AdjacencyGraph;
8+
using bguiz.struct.graph.DirectedAdjacencyGraph;
9+
10+
import bguiz.struct.graph.TopologicalSortGraphResult;
11+
using bguiz.struct.graph.TopologicalSortGraph;
12+
13+
class TopologicalSortGraphTest {
14+
15+
public static function assertArrayEqual <T>(a: Array<T>, b: Array<T>): Void {
16+
Assert.areEqual(a.toString(), b.toString());
17+
Assert.areEqual(a.length, b.length);
18+
var i:Int = 0;
19+
while (i < a.length) {
20+
Assert.areEqual(a[i], b[i]);
21+
++i;
22+
}
23+
}
24+
25+
@Test
26+
public function testConnectedComponentsSearch1() {
27+
var graph:AdjacencyGraph<Int> =
28+
DirectedAdjacencyGraph.make([for (i in 0...4) i]);
29+
30+
graph.addEdge(0, 1);
31+
graph.addEdge(1, 2);
32+
graph.addEdge(2, 3);
33+
34+
var result:TopologicalSortGraphResult<Int> =
35+
graph.topologicalSort();
36+
37+
assertArrayEqual([3,2,1,0], result.reversePostOrderVertices);
38+
}
39+
40+
@Test
41+
public function testConnectedComponentsSearch2() {
42+
var graph:AdjacencyGraph<Int> =
43+
DirectedAdjacencyGraph.make([for (i in 0...4) i]);
44+
45+
graph.addEdge(0, 1);
46+
graph.addEdge(0, 3);
47+
graph.addEdge(1, 3);
48+
graph.addEdge(2, 3);
49+
graph.addEdge(2, 0);
50+
51+
var result:TopologicalSortGraphResult<Int> =
52+
graph.topologicalSort();
53+
54+
assertArrayEqual([3,1,0,2], result.reversePostOrderVertices);
55+
}
56+
57+
@Test
58+
public function testConnectedComponentsSearch3() {
59+
var graph:AdjacencyGraph<Int> =
60+
DirectedAdjacencyGraph.make([for (i in 0...7) i]);
61+
62+
graph.addEdge(0, 1);
63+
graph.addEdge(0, 2);
64+
65+
graph.addEdge(1, 3);
66+
67+
graph.addEdge(2, 3);
68+
graph.addEdge(2, 4);
69+
70+
graph.addEdge(3, 5);
71+
graph.addEdge(3, 6);
72+
73+
graph.addEdge(4, 5);
74+
75+
var result:TopologicalSortGraphResult<Int> =
76+
graph.topologicalSort();
77+
78+
assertArrayEqual([5,6,3,1,4,2,0], result.reversePostOrderVertices);
79+
}
80+
}

0 commit comments

Comments
 (0)