/// <summary> /// Solves the single-source shortest path problem in O(E*ln V) time for a graph with none-negative edge weights. /// </summary> public static Paths <V> Dijkstra <V>(DiGraph <V> graph, V source) where V : class { if (graph == null || source == null) { throw new ArgumentNullException(); } if (!graph.Contains(source)) { throw new ArgumentException(); } if (graph.Edges().Any(e => e.weight < 0)) { throw new ArgumentException(); } var queue = new BinaryHeap <Double, V>(); var distTo = new HashMap <V, Double>(); var edgeTo = new HashMap <V, Edge <V> >(); void Relax(Edge <V> e) { var(v, w) = (e.from, e.to); var weight = new Double(e.weight); if (distTo[v] > distTo[w] + weight) { distTo[w] = distTo[v] + weight; edgeTo[w] = e; if (queue.Contains(w)) { queue.Update(w, distTo[w]); } else { queue.Push(w, distTo[w]); } } } foreach (var v in graph.Vertices()) { distTo[v] = Double.MaxValue; } distTo[source] = new Double(0); queue.Push(source, new Double(0)); while (!queue.IsEmpty()) { var(_, v) = queue.Pop(); foreach (var e in graph.Edges(v)) { Relax(e); } } return(new Paths <V>(source, edgeTo)); }
/// <summary> /// Produces a minimum spanning tree of the given graph using Prim's algorithm in O(E*ln E) time. /// Raises <exception cref="System.InvalidOperationException"> if the graph is not connected. /// </summary> /// <returns>Graph representation of the MST</returns> public static Graph <V> Prim <V>(Graph <V> graph) { if (graph == null) { throw new ArgumentNullException(); } if (!graph.IsConnected()) { throw new InvalidOperationException(); } // Lazy variant of Prim's algorithm: // Grow a tree by adding the smallest edge pointing out of it var tree = new Graph <V>(); var queue = new BinaryHeap <Edge <V> >(); var vertices = new HashSet <V>(); // vertices in the tree // Adds edges of v pointing out of the tree to the PQ void Visit(V v) { vertices.Add(v); foreach (var e in graph.Edges(v)) { if (!vertices.Contains(e.to)) { queue.Push(e); // If e.to is already in the tree then e (or rather its complement) is in the queue } } } if (!graph.IsEmpty()) { Visit(graph.Vertices().First()); } while (!queue.IsEmpty()) { var e = queue.Pop(); if (vertices.Contains(e.to)) { continue; // Otherwise we will form a cycle } tree.Add(e); Visit(e.to); } return(tree); }
/// <summary> /// Produces a minimum spanning tree of the given graph using Kruskal's algorithm in O(E*ln V) time. /// Raises <exception cref="System.InvalidOperationException"> if the graph is not connected. /// </summary> /// <returns>Graph representation of the MST</returns> public static Graph <V> Kruskal <V>(Graph <V> graph) { if (graph == null) { throw new ArgumentNullException(); } if (!graph.IsConnected()) { throw new InvalidOperationException(); // We would need to produce a minimum spanning forest instead } // Kruskal's algorithm is a special case of the greedy MST algorithm: // - Maintain a forest of trees (initially individual vertices of the graph) // - Repreatedly add edges in descending order of weight to combine forests into a tree // (Exclude edges that connect vertices that are already part of the same tree.) var tree = new Graph <V>(); var n = 0; // no. of vertices in the MST var queue = new BinaryHeap <Edge <V> >(); foreach (var e in graph.Edges()) { queue.Push(e); } var vertices = graph.Vertices(); var N = vertices.Count(); // no. of vertices in the original graph var uf = new QuickUnion <V>(vertices.ToArray()); // The MST of a connected graph must contain exactly N-1 edges while (n < N - 1) { var e = queue.Pop(); if (!uf.Connected(e.from, e.to)) { uf.Union(e.from, e.to); tree.Add(e); n++; } } return(tree); }