/// <summary>
        /// Tries to compute the shortest paths in an unweighted graph with the Bellman-Ford's algorithm. Shortest paths are computed with the distance between the vertices. Returns true if successful; otherwise false.
        /// </summary>
        /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam>
        /// <param name="graph">The graph structure that implements <see cref="IGraph{TVertex}"/>.</param>
        /// <param name="source">The source vertex for which the shortest paths are computed.</param>
        /// <param name="shortestPaths">The <see cref="UnweightedGraphShortestPaths{TVertex}"/> object that contains the shortest paths of the graph if the algorithm was successful; otherwise null.</param>
        /// <returns>Returns true if the shortest paths were successfully computed; otherwise false. Also returns false if the given source vertex does not belong to the graph.</returns>
        public static bool TryGetBellmanFordShortestPaths <TVertex>(this IGraph <TVertex> graph, TVertex source, out UnweightedGraphShortestPaths <TVertex> shortestPaths)
            where TVertex : IComparable <TVertex>
        {
            shortestPaths = null;

            if (!graph.ContainsVertex(source))
            {
                return(false);
            }

            // A dictionary holding a vertex as key and its previous vertex in the path as value.
            var previousVertices = new Dictionary <TVertex, TVertex>();
            // A dictionary holding a vertex as key and the distance from the source vertex as value.
            var pathDistance = new Dictionary <TVertex, int>();

            // Add source vertex to computed distances
            pathDistance.Add(source, 0);

            // Get all edges and sort them by their source and then by their destination vertex to create a consistent shortest paths output.
            var allEdges = graph.Edges.ToList();

            if (allEdges.Count > 0)
            {
                allEdges.QuickSort((x, y) =>
                {
                    int cmp = x.Source.CompareTo(y.Source);
                    if (cmp == 0)
                    {
                        cmp = x.Destination.CompareTo(y.Destination);
                    }
                    return(cmp);
                });
            }

            // We relax all edges n - 1 times and if at the n-th step a relaxation is needed we have a negative cycle
            int lastStep = graph.VerticesCount - 1;

            for (int i = 0; i < graph.VerticesCount; i++)
            {
                foreach (var edge in allEdges)
                {
                    var edgeSource      = edge.Source;
                    var edgeDestination = edge.Destination;

                    // If we have computed the path to the the source vertex of the edge
                    if (pathDistance.ContainsKey(edgeSource))
                    {
                        int curDistance = pathDistance[edgeSource];

                        // If the edge destination is the source we continue with the next edge
                        if (object.Equals(source, edgeDestination))
                        {
                            continue;
                        }

                        int newDistance = curDistance + 1;

                        // If this distance is bigger or equal than an already computed distance we continue with the next edge
                        if (pathDistance.ContainsKey(edgeDestination))
                        {
                            if (newDistance.CompareTo(pathDistance[edgeDestination]) >= 0)
                            {
                                continue;
                            }
                        }

                        if (i == lastStep)// if we need to relax on the last iteration we have a negative cycle
                        {
                            return(false);
                        }

                        // Else we save the path
                        previousVertices[edgeDestination] = edgeSource;
                        pathDistance[edgeDestination]     = newDistance;
                    }
                }
            }

            // Remove source vertex from path distance dictionary
            pathDistance.Remove(source);

            shortestPaths = new UnweightedGraphShortestPaths <TVertex>(source, previousVertices, pathDistance);
            return(true);
        }
Пример #2
0
        /// <summary>
        /// Uses Dijkstra's algorithm to compute the shortest paths in an unweighted graph. Shortest paths are computed with the distance between the vertices. Returns an <see cref="UnweightedGraphShortestPaths{TVertex}"/> object containg the shortest paths.
        /// </summary>
        /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam>
        /// <param name="graph">The graph structure that implements <see cref="IGraph{TVertex}"/>.</param>
        /// <param name="source">The source vertex for which the shortest paths are computed.</param>
        /// <returns>Returns a <see cref="UnweightedGraphShortestPaths{TVertex}"/> containing the shortest paths for the given source vertex.</returns>
        public static UnweightedGraphShortestPaths <TVertex> DijkstraShortestPaths <TVertex>(this IGraph <TVertex> graph, TVertex source)
            where TVertex : IComparable <TVertex>
        {
            if (!graph.ContainsVertex(source))
            {
                throw new ArgumentException("Vertex does not belong to the graph!");
            }

            // A dictionary holding a vertex as key and its previous vertex in the path as value.
            var previousVertices = new Dictionary <TVertex, TVertex>();
            // A dictionary holding a vertex as key and the distance from the source vertex as value.
            var pathDistance = new Dictionary <TVertex, int>();
            // Comparer for the key-value pair in the sorted set
            var kvpComparer = Comparer <KeyValuePair <int, TVertex> > .Create((x, y) =>
            {
                var cmp = x.Key.CompareTo(y.Key);
                if (cmp == 0)
                {
                    cmp = x.Value.CompareTo(y.Value);
                }
                return(cmp);
            });

            // Sorted set containing the vertices for computing. Having a kvp with the distance from the source vertex as a key and the vertex as a value
            var priorityQueue = new MinPriorityQueue <int, TVertex>(kvpComparer);

            // Add the source vertex
            priorityQueue.Enqueue(0, source);

            while (priorityQueue.Count > 0)
            {
                var     curKVP      = priorityQueue.Dequeue();
                TVertex curVertex   = curKVP.Value;
                int     curDistance = curKVP.Key;

                foreach (var edge in graph.OutgoingEdgesSorted(curVertex))
                {
                    var edgeDestination = edge.Destination;

                    // If the edge destination is the source we continue with the next edge
                    if (object.Equals(source, edgeDestination))
                    {
                        continue;
                    }

                    int newDistance = curDistance + 1;

                    // If this distance is bigger or equal than an already computed distance we continue with the next edge
                    if (pathDistance.ContainsKey(edgeDestination))
                    {
                        if (newDistance.CompareTo(pathDistance[edgeDestination]) >= 0)
                        {
                            continue;
                        }
                    }

                    // Else we save the path
                    previousVertices[edgeDestination] = curVertex;
                    pathDistance[edgeDestination]     = newDistance;

                    // Add the destination vertex for computing
                    priorityQueue.Enqueue(newDistance, edgeDestination);
                }
            }

            var shortestPaths = new UnweightedGraphShortestPaths <TVertex>(source, previousVertices, pathDistance);

            return(shortestPaths);
        }