Skip to content

Commit 6603595

Browse files
committed
A* search
1 parent 90e47aa commit 6603595

40 files changed

+528
-120
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ TODO: implement trie compression.
193193
- [X] Floyd-Warshall algorithm ([implementation](https://github.com/justcoding121/Advanced-Algorithms/blob/master/src/Advanced.Algorithms/Graph/ShortestPath/Floyd-Warshall.cs) | [tests](https://github.com/justcoding121/Advanced-Algorithms/blob/master/tests/Advanced.Algorithms.Tests/Graph/ShortestPath/FloydWarshall_Tests.cs))
194194
- [X] Johnson's algorithm ([implementation](https://github.com/justcoding121/Advanced-Algorithms/blob/master/src/Advanced.Algorithms/Graph/ShortestPath/Johnsons.cs) | [tests](https://github.com/justcoding121/Advanced-Algorithms/blob/master/tests/Advanced.Algorithms.Tests/Graph/ShortestPath/Johnson_Tests.cs))
195195
- [X] Travelling salesman problem ([implementation](https://github.com/justcoding121/Advanced-Algorithms/blob/master/src/Advanced.Algorithms/Graph/ShortestPath/TravellingSalesman.cs) | [tests](https://github.com/justcoding121/Advanced-Algorithms/blob/master/tests/Advanced.Algorithms.Tests/Graph/ShortestPath/TravellingSalesman_Tests.cs))
196+
- [X] A* algorithm ([implementation](https://github.com/justcoding121/Advanced-Algorithms/blob/master/src/Advanced.Algorithms/Graph/ShortestPath/AStar.cs) | [tests](https://github.com/justcoding121/Advanced-Algorithms/blob/master/tests/Advanced.Algorithms.Tests/Graph/ShortestPath/AStar_Tests.cs)) using Fibornacci heap.
196197

197198
#### Matching
198199

@@ -203,6 +204,10 @@ TODO: implement trie compression.
203204

204205
- [X] Minimum cut ([implementation](https://github.com/justcoding121/Advanced-Algorithms/blob/master/src/Advanced.Algorithms/Graph/Cut/MinimumCut.cs) | [tests](https://github.com/justcoding121/Advanced-Algorithms/blob/master/tests/Advanced.Algorithms.Tests/Graph/Cut/MinCut_Tests.cs)) using Edmonds Karp's improved Ford Fulkerson max flow algorithm
205206

207+
#### Cycle
208+
209+
- [X] Cycle detection ([implementation](https://github.com/justcoding121/Advanced-Algorithms/blob/master/src/Advanced.Algorithms/Graph/Cycle/CycleDetection.cs) | [tests](https://github.com/justcoding121/Advanced-Algorithms/blob/master/tests/Advanced.Algorithms.Tests/Graph/Cycle/CycleDetection_Tests.cs))
210+
206211
#### Search
207212

208213
- [X] Depth first ([implementation](https://github.com/justcoding121/Advanced-Algorithms/blob/master/src/Advanced.Algorithms/Graph/Search/DepthFirst.cs) | [tests](https://github.com/justcoding121/Advanced-Algorithms/blob/master/tests/Advanced.Algorithms.Tests/Graph/Search/DepthFirst_Tests.cs))

src/Advanced.Algorithms/Advanced.Algorithms.Docs.csproj

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="..\packages\Microsoft.Net.Compilers.2.9.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.2.9.0\build\Microsoft.Net.Compilers.props')" />
34
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
45
<PropertyGroup>
56
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -12,6 +13,8 @@
1213
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1314
<FileAlignment>512</FileAlignment>
1415
<TargetFrameworkProfile />
16+
<NuGetPackageImportStamp>
17+
</NuGetPackageImportStamp>
1518
</PropertyGroup>
1619
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
1720
<DebugSymbols>true</DebugSymbols>
@@ -23,7 +26,7 @@
2326
<WarningLevel>4</WarningLevel>
2427
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
2528
<DocumentationFile>bin\Debug\Advanced.Algorithms.xml</DocumentationFile>
26-
<LangVersion>latest</LangVersion>
29+
<LangVersion>Latest</LangVersion>
2730
</PropertyGroup>
2831
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
2932
<DebugType>pdbonly</DebugType>
@@ -119,6 +122,7 @@
119122
<Compile Include="DataStructures\Tree\RedBlackTree.cs" />
120123
<Compile Include="DataStructures\Tree\RTree.cs" />
121124
<Compile Include="DataStructures\Tree\SegmentTree.cs" />
125+
<Compile Include="DataStructures\Tree\Shared\ArrayComparer.cs" />
122126
<Compile Include="DataStructures\Tree\Shared\BSTEnumerator.cs" />
123127
<Compile Include="DataStructures\Tree\Shared\BSTExtensions.cs" />
124128
<Compile Include="DataStructures\Tree\Shared\BSTNodeBase.cs" />
@@ -165,6 +169,7 @@
165169
<Compile Include="Graph\Search\BiDirectional.cs" />
166170
<Compile Include="Graph\Search\BreadthFirst.cs" />
167171
<Compile Include="Graph\Search\DepthFirst.cs" />
172+
<Compile Include="Graph\ShortestPath\AStar.cs" />
168173
<Compile Include="Graph\ShortestPath\Bellman-Ford.cs" />
169174
<Compile Include="Graph\ShortestPath\Dijikstra.cs" />
170175
<Compile Include="Graph\ShortestPath\Floyd-Warshall.cs" />
@@ -195,7 +200,16 @@
195200
<Compile Include="String\Search\RabinKarp.cs" />
196201
<Compile Include="String\Search\ZAlgorithm.cs" />
197202
</ItemGroup>
203+
<ItemGroup>
204+
<None Include="packages.config" />
205+
</ItemGroup>
198206
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
207+
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
208+
<PropertyGroup>
209+
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
210+
</PropertyGroup>
211+
<Error Condition="!Exists('..\packages\Microsoft.Net.Compilers.2.9.0\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Net.Compilers.2.9.0\build\Microsoft.Net.Compilers.props'))" />
212+
</Target>
199213
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
200214
Other similar extension points exist, see Microsoft.Common.targets.
201215
<Target Name="BeforeBuild">

src/Advanced.Algorithms/Graph/Connectivity/TarjansBiConnected.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ public class TarjansBiConnected<T>
1313
/// </summary>
1414
public bool IsBiConnected(Graph<T> graph)
1515
{
16-
var articulationAlgo = new TarjansArticulationFinder<T>();
17-
return articulationAlgo.FindArticulationPoints(graph).Count == 0;
16+
var algorithm = new TarjansArticulationFinder<T>();
17+
return algorithm.FindArticulationPoints(graph).Count == 0;
1818
}
1919
}
2020
}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
using Advanced.Algorithms.DataStructures;
2+
using Advanced.Algorithms.DataStructures.Graph.AdjacencyList;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
7+
namespace Advanced.Algorithms.Graph
8+
{
9+
/// <summary>
10+
/// A* algorithm implementation using Fibornacci Heap.
11+
/// </summary>
12+
public class AStarShortestPath<T, W> where W : IComparable
13+
{
14+
readonly IShortestPathOperators<W> operators;
15+
readonly IAStarHeuristic<T, W> heuristic;
16+
17+
public AStarShortestPath(IShortestPathOperators<W> operators, IAStarHeuristic<T, W> heuristic)
18+
{
19+
this.operators = operators;
20+
this.heuristic = heuristic;
21+
}
22+
23+
/// <summary>
24+
/// Search path to target using the heuristic.
25+
/// </summary>
26+
public ShortestPathResult<T, W> FindShortestPath(WeightedDiGraph<T, W> graph, T source, T destination)
27+
{
28+
//regular argument checks
29+
if (graph?.FindVertex(source) == null || graph.FindVertex(destination) == null)
30+
{
31+
throw new ArgumentException();
32+
}
33+
34+
//track progress for distance to each Vertex from source
35+
var progress = new Dictionary<T, W>();
36+
37+
//trace our current path by mapping current vertex to its Parent
38+
var parentMap = new Dictionary<T, T>();
39+
40+
//min heap to pick next closest vertex
41+
var minHeap = new FibornacciMinHeap<AStarWrap<T, W>>();
42+
//keep references of heap Node for decrement key operation
43+
var heapMapping = new Dictionary<T, AStarWrap<T, W>>();
44+
45+
//add vertices to min heap and progress map
46+
foreach (var vertex in graph.Vertices)
47+
{
48+
//init parent
49+
parentMap.Add(vertex.Key, default(T));
50+
51+
//init to max value
52+
progress.Add(vertex.Key, operators.MaxValue);
53+
54+
if (vertex.Key.Equals(source))
55+
{
56+
continue;
57+
}
58+
}
59+
60+
//start from source vertex as current
61+
var current = new AStarWrap<T, W>(heuristic, destination)
62+
{
63+
Distance = operators.DefaultValue,
64+
Vertex = source
65+
};
66+
67+
//insert neighbour in heap
68+
minHeap.Insert(current);
69+
heapMapping[source] = current;
70+
71+
//until heap is empty
72+
while (minHeap.Count > 0)
73+
{
74+
//next min vertex to visit
75+
current = minHeap.ExtractMin();
76+
heapMapping.Remove(current.Vertex);
77+
78+
//no path exists, so return max value
79+
if (current.Distance.Equals(operators.MaxValue))
80+
{
81+
return new ShortestPathResult<T, W>(null, operators.MaxValue);
82+
}
83+
84+
//visit neighbours of current
85+
foreach (var neighbour in graph.Vertices[current.Vertex].OutEdges.Where(x => !x.Key.Value.Equals(source)))
86+
{
87+
//new distance to neighbour
88+
var newDistance = operators.Sum(current.Distance,
89+
graph.Vertices[current.Vertex].OutEdges[neighbour.Key]);
90+
91+
//current distance to neighbour
92+
var existingDistance = progress[neighbour.Key.Value];
93+
94+
//update distance if new is better
95+
if (newDistance.CompareTo(existingDistance) < 0)
96+
{
97+
progress[neighbour.Key.Value] = newDistance;
98+
99+
if (heapMapping.ContainsKey(neighbour.Key.Value))
100+
{
101+
//decrement distance to neighbour in heap
102+
var decremented = new AStarWrap<T, W>(heuristic, destination) { Distance = newDistance, Vertex = neighbour.Key.Value };
103+
minHeap.DecrementKey(heapMapping[neighbour.Key.Value], decremented);
104+
heapMapping[neighbour.Key.Value] = decremented;
105+
106+
}
107+
else
108+
{
109+
//insert neighbour in heap
110+
var discovered = new AStarWrap<T, W>(heuristic, destination) { Distance = newDistance, Vertex = neighbour.Key.Value };
111+
minHeap.Insert(discovered);
112+
heapMapping[neighbour.Key.Value] = discovered;
113+
}
114+
115+
//trace parent
116+
parentMap[neighbour.Key.Value] = current.Vertex;
117+
}
118+
}
119+
}
120+
121+
return tracePath(graph, parentMap, source, destination);
122+
}
123+
124+
/// <summary>
125+
/// Trace back path from destination to source using parent map.
126+
/// </summary>
127+
private ShortestPathResult<T, W> tracePath(WeightedDiGraph<T, W> graph, Dictionary<T, T> parentMap, T source, T destination)
128+
{
129+
//trace the path
130+
var pathStack = new Stack<T>();
131+
132+
pathStack.Push(destination);
133+
134+
var currentV = destination;
135+
while (!Equals(currentV, default(T)) && !Equals(parentMap[currentV], default(T)))
136+
{
137+
pathStack.Push(parentMap[currentV]);
138+
currentV = parentMap[currentV];
139+
}
140+
141+
//return result
142+
var resultPath = new List<T>();
143+
var resultLength = operators.DefaultValue;
144+
while (pathStack.Count > 0)
145+
{
146+
resultPath.Add(pathStack.Pop());
147+
}
148+
149+
for (int i = 0; i < resultPath.Count - 1; i++)
150+
{
151+
resultLength = operators.Sum(resultLength,
152+
graph.Vertices[resultPath[i]].OutEdges[graph.Vertices[resultPath[i + 1]]]);
153+
}
154+
155+
return new ShortestPathResult<T, W>(resultPath, resultLength);
156+
}
157+
}
158+
159+
/// <summary>
160+
/// Search heuristic used by A* search algorithm.
161+
/// </summary>
162+
public interface IAStarHeuristic<T, W> where W : IComparable
163+
{
164+
/// <summary>
165+
/// Return the distance to target for given sourcevertex as computed by the hueristic used for A* search.
166+
/// </summary>
167+
W HueristicDistanceToTarget(T sourceVertex, T targetVertex);
168+
}
169+
170+
//Node for our Fibornacci heap
171+
internal class AStarWrap<T, W> : IComparable where W : IComparable
172+
{
173+
private IAStarHeuristic<T, W> heuristic;
174+
private T destinationVertex;
175+
internal AStarWrap(IAStarHeuristic<T, W> heuristic, T destinationVertex)
176+
{
177+
this.heuristic = heuristic;
178+
this.destinationVertex = destinationVertex;
179+
}
180+
181+
internal T Vertex { get; set; }
182+
internal W Distance { get; set; }
183+
184+
//compare distance to target using the heuristic provided
185+
public int CompareTo(object obj)
186+
{
187+
if (this == obj)
188+
{
189+
return 0;
190+
}
191+
192+
var result1 = heuristic.HueristicDistanceToTarget(Vertex, destinationVertex);
193+
var result2 = heuristic.HueristicDistanceToTarget((obj as AStarWrap<T, W>).Vertex, destinationVertex);
194+
195+
return result1.CompareTo(result2);
196+
}
197+
}
198+
}

src/Advanced.Algorithms/Graph/ShortestPath/Bellman-Ford.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ public BellmanFordShortestPath(IShortestPathOperators<W> operators)
1616
}
1717

1818
/// <summary>
19-
/// Get shortest distance to target.
19+
/// Find shortest distance to target.
2020
/// </summary>
21-
public ShortestPathResult<T, W> GetShortestPath(WeightedDiGraph<T, W> graph, T source, T destination)
21+
public ShortestPathResult<T, W> FindShortestPath(WeightedDiGraph<T, W> graph, T source, T destination)
2222
{
2323
//regular argument checks
2424
if (graph == null || graph.FindVertex(source) == null

0 commit comments

Comments
 (0)