Ai
1 Star 1 Fork 0

AndyZhang/C-Sharp-Algorithms

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
BreadthFirstShortestPaths.cs 10.45 KB
一键复制 编辑 原始数据 按行查看 历史
Ivandro Ismael 提交于 2018-05-21 07:50 +08:00 . remove redundant "else" / "else if"
/***
* Computes Shortest-Paths for Unweighted Graphs using the Breadth-First Search algorithm.
* It provides the capability to find shortest-paths from a single-source and multiple-sources, in addition to looking up reachable and unreachable nodes.
*/
using System;
using System.Diagnostics;
using System.Collections.Generic;
using Algorithms.Common;
using DataStructures.Graphs;
namespace Algorithms.Graphs
{
public class BreadthFirstShortestPaths<T> where T : IComparable<T>
{
private int _edgesCount { get; set; }
private int _verticesCount { get; set; }
private bool[] _visited { get; set; }
private Int64[] _distances { get; set; }
private int[] _predecessors { get; set; }
// A dictionary that maps node-values to integer indeces
private Dictionary<T, int> _nodesToIndices { get; set; }
// A dictionary that maps integer index to node-value
private Dictionary<int, T> _indicesToNodes { get; set; }
// A const that represent an infinite distance
private const Int64 INFINITY = Int64.MaxValue;
/// <summary>
/// CONSTRUCTOR.
/// Breadth First Searcher from Single Source.
/// </summary>
public BreadthFirstShortestPaths(IGraph<T> Graph, T Source)
{
if (Graph == null)
throw new ArgumentNullException();
if (!Graph.HasVertex(Source))
throw new ArgumentException("The source vertex doesn't belong to graph.");
// Init
_initializeDataMembers(Graph);
// Single source BFS
_breadthFirstSearch(Graph, Source);
//bool optimalityConditionsSatisfied = checkOptimalityConditions (Graph, Source);
Debug.Assert(checkOptimalityConditions(Graph, Source));
}
/// <summary>
/// CONSTRUCTOR.
/// Breadth First Searcher from Multiple Sources.
/// </summary>
public BreadthFirstShortestPaths(IGraph<T> Graph, IList<T> Sources)
{
if (Graph == null)
throw new ArgumentNullException();
if (Sources == null || Sources.Count == 0)
throw new ArgumentException("Sources list is either null or empty.");
// Init
_initializeDataMembers(Graph);
// Multiple sources BFS
_breadthFirstSearch(Graph, Sources);
}
/************************************************************************************************************/
/// <summary>
/// Constructors helper function. Initializes some of the data memebers.
/// </summary>
private void _initializeDataMembers(IGraph<T> Graph)
{
_edgesCount = Graph.EdgesCount;
_verticesCount = Graph.VerticesCount;
_visited = new bool[_verticesCount];
_distances = new Int64[_verticesCount];
_predecessors = new int[_verticesCount];
_nodesToIndices = new Dictionary<T, int>();
_indicesToNodes = new Dictionary<int, T>();
// Reset the visited, distances and predeccessors arrays
int i = 0;
foreach (var node in Graph.Vertices)
{
if (i >= _verticesCount)
break;
_visited[i] = false;
_distances[i] = INFINITY;
_predecessors[i] = -1;
_nodesToIndices.Add(node, i);
_indicesToNodes.Add(i, node);
++i;
}
}
/// <summary>
/// Privat helper. Breadth First Search from Single Source.
/// </summary>
private void _breadthFirstSearch(IGraph<T> graph, T source)
{
// Set distance to current to zero
_distances[_nodesToIndices[source]] = 0;
// Set current to visited: true.
_visited[_nodesToIndices[source]] = true;
var queue = new Queue<T>(_verticesCount);
queue.Enqueue(source);
while (queue.Count > 0)
{
var current = queue.Dequeue();
int indexOfCurrent = _nodesToIndices[current];
foreach (var adjacent in graph.Neighbours(current))
{
int indexOfAdjacent = _nodesToIndices[adjacent];
if (!_visited[indexOfAdjacent])
{
_predecessors[indexOfAdjacent] = indexOfCurrent;
_distances[indexOfAdjacent] = _distances[indexOfCurrent] + 1;
_visited[indexOfAdjacent] = true;
queue.Enqueue(adjacent);
}
}//end-foreach
}//end-while
}
/// <summary>
/// Privat helper. Breadth First Search from Multiple Sources.
/// </summary>
private void _breadthFirstSearch(IGraph<T> graph, IList<T> sources)
{
// Define helper variables.
var queue = new Queue<T>(_verticesCount);
foreach (var source in sources)
{
if (!graph.HasVertex(source))
throw new Exception("Graph doesn't has a vertex '" + source + "'");
int index = _nodesToIndices[source];
_distances[index] = 0;
_visited[index] = true;
queue.Enqueue(source);
}
while (queue.Count > 0)
{
var current = queue.Dequeue();
int indexOfCurrent = _nodesToIndices[current];
foreach (var adjacent in graph.Neighbours(current))
{
int indexOfAdjacent = _nodesToIndices[adjacent];
if (!_visited[indexOfAdjacent])
{
_predecessors[indexOfAdjacent] = indexOfCurrent;
_distances[indexOfAdjacent] = _distances[indexOfCurrent] + 1;
_visited[indexOfAdjacent] = true;
queue.Enqueue(adjacent);
}
}//end-foreach
}//end-while
}
/// <summary>
/// Private helper. Checks optimality conditions for single source
/// </summary>
private bool checkOptimalityConditions(IGraph<T> graph, T source)
{
int indexOfSource = _nodesToIndices[source];
// check that the distance of s = 0
if (_distances[indexOfSource] != 0)
{
Console.WriteLine("Distance of source '" + source + "' to itself = " + _distances[indexOfSource]);
return false;
}
// check that for each edge v-w dist[w] <= dist[v] + 1
// provided v is reachable from s
foreach (var node in graph.Vertices)
{
int v = _nodesToIndices[node];
foreach (var adjacent in graph.Neighbours(node))
{
int w = _nodesToIndices[adjacent];
if (HasPathTo(node) != HasPathTo(adjacent))
{
Console.WriteLine("edge " + node + "-" + adjacent);
Console.WriteLine("hasPathTo(" + node + ") = " + HasPathTo(node));
Console.WriteLine("hasPathTo(" + adjacent + ") = " + HasPathTo(adjacent));
return false;
}
if (HasPathTo(node) && (_distances[w] > _distances[v] + 1))
{
Console.WriteLine("edge " + node + "-" + adjacent);
Console.WriteLine("distanceTo[" + node + "] = " + _distances[v]);
Console.WriteLine("distanceTo[" + adjacent + "] = " + _distances[w]);
return false;
}
}
}
// check that v = edgeTo[w] satisfies distTo[w] + distTo[v] + 1
// provided v is reachable from source
foreach (var node in graph.Vertices)
{
int w = _nodesToIndices[node];
if (!HasPathTo(node) || node.IsEqualTo(source))
continue;
int v = _predecessors[w];
if (_distances[w] != _distances[v] + 1)
{
Console.WriteLine("shortest path edge " + v + "-" + w);
Console.WriteLine("distanceTo[" + v + "] = " + _distances[v]);
Console.WriteLine("distanceTo[" + w + "] = " + _distances[w]);
return false;
}
}
return true;
}
/************************************************************************************************************/
/// <summary>
/// Determines whether there is a path from the source vertex to this specified vertex.
/// </summary>
public bool HasPathTo(T destination)
{
if (!_nodesToIndices.ContainsKey(destination))
throw new Exception("Graph doesn't have the specified vertex.");
int dstIndex = _nodesToIndices[destination];
return (_visited[dstIndex]);
}
/// <summary>
/// Returns the distance between the source vertex and the specified vertex.
/// </summary>
public long DistanceTo(T destination)
{
if (!_nodesToIndices.ContainsKey(destination))
throw new Exception("Graph doesn't have the specified vertex.");
int dstIndex = _nodesToIndices[destination];
return (_distances[dstIndex]);
}
/// <summary>
/// Returns an enumerable collection of nodes that specify the shortest path from the source vertex to the destination vertex.
/// </summary>
public IEnumerable<T> ShortestPathTo(T destination)
{
if (!_nodesToIndices.ContainsKey(destination))
throw new Exception("Graph doesn't have the specified vertex.");
if (!HasPathTo(destination))
return null;
int dstIndex = _nodesToIndices[destination];
var stack = new DataStructures.Lists.Stack<T>();
int index;
for (index = dstIndex; _distances[index] != 0; index = _predecessors[index])
stack.Push(_indicesToNodes[index]);
// Push the source vertex
stack.Push(_indicesToNodes[index]);
return stack;
}
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C#
1
https://gitee.com/strongandyzhang/C-Sharp-Algorithms.git
git@gitee.com:strongandyzhang/C-Sharp-Algorithms.git
strongandyzhang
C-Sharp-Algorithms
C-Sharp-Algorithms
master

搜索帮助