dijkstra SSSP
parent
031a0e1e23
commit
5b1c05819e
|
@ -224,10 +224,10 @@ namespace MoonTools.Core.Graph
|
||||||
}
|
}
|
||||||
sccs.Clear();
|
sccs.Clear();
|
||||||
|
|
||||||
var preorder = new PooledDictionary<TNode, uint>();
|
var preorder = new PooledDictionary<TNode, uint>(ClearMode.Always);
|
||||||
var lowlink = new PooledDictionary<TNode, uint>();
|
var lowlink = new PooledDictionary<TNode, uint>(ClearMode.Always);
|
||||||
var sccFound = new PooledDictionary<TNode, bool>();
|
var sccFound = new PooledDictionary<TNode, bool>(ClearMode.Always);
|
||||||
var sccQueue = new PooledStack<TNode>();
|
var sccQueue = new PooledStack<TNode>(ClearMode.Always);
|
||||||
|
|
||||||
uint preorderCounter = 0;
|
uint preorderCounter = 0;
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ namespace MoonTools.Core.Graph
|
||||||
if (lowlink[v] == preorder[v])
|
if (lowlink[v] == preorder[v])
|
||||||
{
|
{
|
||||||
sccFound[v] = true;
|
sccFound[v] = true;
|
||||||
var scc = new PooledList<TNode>
|
var scc = new PooledList<TNode>(ClearMode.Always)
|
||||||
{
|
{
|
||||||
v
|
v
|
||||||
};
|
};
|
||||||
|
|
|
@ -112,5 +112,50 @@ namespace MoonTools.Core.Graph
|
||||||
|
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<(TNode, TNode, int)> DijkstraSingleSourceShortestPath(TNode source)
|
||||||
|
{
|
||||||
|
CheckNodes(source);
|
||||||
|
|
||||||
|
var distance = new PooledDictionary<TNode, int>(ClearMode.Always);
|
||||||
|
var previous = new PooledDictionary<TNode, TNode>(ClearMode.Always);
|
||||||
|
|
||||||
|
foreach (var node in Nodes)
|
||||||
|
{
|
||||||
|
distance[node] = int.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
distance[source] = 0;
|
||||||
|
|
||||||
|
var q = Nodes.ToPooledList();
|
||||||
|
|
||||||
|
while (q.Count > 0)
|
||||||
|
{
|
||||||
|
var node = q.MinBy(n => distance[n]).First();
|
||||||
|
q.Remove(node);
|
||||||
|
if (distance[node] == int.MaxValue) { break; }
|
||||||
|
|
||||||
|
foreach (var neighbor in Neighbors(node))
|
||||||
|
{
|
||||||
|
var alt = distance[node] + Weight(node, neighbor);
|
||||||
|
if (alt < distance[neighbor])
|
||||||
|
{
|
||||||
|
distance[neighbor] = alt;
|
||||||
|
previous[neighbor] = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var node in Nodes)
|
||||||
|
{
|
||||||
|
if (!node.Equals(source))
|
||||||
|
{
|
||||||
|
yield return (node, previous[node], distance[node]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
distance.Dispose();
|
||||||
|
previous.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -32,9 +32,9 @@ namespace MoonTools.Core.Graph
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var colors = new PooledDictionary<TNode, Color>();
|
var colors = new PooledDictionary<TNode, Color>(ClearMode.Always);
|
||||||
var d = new PooledDictionary<TNode, int>();
|
var d = new PooledDictionary<TNode, int>(ClearMode.Always);
|
||||||
var partition = new PooledDictionary<TNode, int>();
|
var partition = new PooledDictionary<TNode, int>(ClearMode.Always);
|
||||||
|
|
||||||
foreach (var node in Nodes)
|
foreach (var node in Nodes)
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ namespace MoonTools.Core.Graph
|
||||||
partition[start] = 1;
|
partition[start] = 1;
|
||||||
d[start] = 0;
|
d[start] = 0;
|
||||||
|
|
||||||
var stack = new PooledStack<TNode>();
|
var stack = new PooledStack<TNode>(ClearMode.Always);
|
||||||
stack.Push(start);
|
stack.Push(start);
|
||||||
|
|
||||||
while (stack.Count > 0)
|
while (stack.Count > 0)
|
||||||
|
|
|
@ -221,5 +221,48 @@ namespace Tests
|
||||||
// have to call Count() because otherwise the lazy evaluation wont trigger
|
// have to call Count() because otherwise the lazy evaluation wont trigger
|
||||||
myGraph.Invoking(x => x.AStarShortestPath('a', 'z', (x, y) => 1).Count()).Should().Throw<System.ArgumentException>();
|
myGraph.Invoking(x => x.AStarShortestPath('a', 'z', (x, y) => 1).Count()).Should().Throw<System.ArgumentException>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DijkstraSingleSourceShortestPath()
|
||||||
|
{
|
||||||
|
var run = new MoveTypeEdgeData { moveType = MoveType.Run };
|
||||||
|
var jump = new MoveTypeEdgeData { moveType = MoveType.Jump };
|
||||||
|
var wallJump = new MoveTypeEdgeData { moveType = MoveType.WallJump };
|
||||||
|
|
||||||
|
var myGraph = new DirectedWeightedGraph<char, MoveTypeEdgeData>();
|
||||||
|
myGraph.AddNodes('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
|
||||||
|
myGraph.AddEdges(
|
||||||
|
('a', 'b', 2, run),
|
||||||
|
('a', 'c', 3, run),
|
||||||
|
('a', 'e', 4, wallJump),
|
||||||
|
('b', 'd', 2, jump),
|
||||||
|
('b', 'e', 1, run),
|
||||||
|
('c', 'g', 4, jump),
|
||||||
|
('c', 'h', 11, run),
|
||||||
|
('d', 'c', 3, jump),
|
||||||
|
('d', 'f', 2, run),
|
||||||
|
('d', 'h', 3, wallJump),
|
||||||
|
('e', 'f', 5, run),
|
||||||
|
('f', 'd', 2, run),
|
||||||
|
('f', 'h', 6, wallJump),
|
||||||
|
('g', 'h', 7, run),
|
||||||
|
('h', 'f', 1, jump)
|
||||||
|
);
|
||||||
|
|
||||||
|
myGraph
|
||||||
|
.DijkstraSingleSourceShortestPath('a')
|
||||||
|
.Should()
|
||||||
|
.Contain(('b', 'a', 2)).And
|
||||||
|
.Contain(('c', 'a', 3)).And
|
||||||
|
.Contain(('d', 'b', 4)).And
|
||||||
|
.Contain(('e', 'b', 3)).And
|
||||||
|
.Contain(('f', 'd', 6)).And
|
||||||
|
.Contain(('g', 'c', 7)).And
|
||||||
|
.Contain(('h', 'd', 7)).And
|
||||||
|
.HaveCount(7);
|
||||||
|
|
||||||
|
// have to call Count() because otherwise the lazy evaluation wont trigger
|
||||||
|
myGraph.Invoking(x => x.DijkstraSingleSourceShortestPath('z').Count()).Should().Throw<System.ArgumentException>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue