/// <summary> /// Retrieves the shortest path from one node pf a graph edge to the other, /// or calculates it if it has not yet been found. /// </summary> /// <param name="edge">The graph edge.</param> /// <returns>The shortest path from outside to inside, not containing either and ordered from inside to outside.</returns> public ushort[] GetShortestPath(GraphEdge edge) { return(GetShortestPath(edge.outside, edge.inside)); }
/// <summary> /// Retrieves the path distance from one node pf a graph edge to the other, /// or calculates it if it has not yet been found. /// </summary> /// <param name="edge">The graph edge.</param> /// <returns>The length of the graph edge (equals the amount of edges /// traversed).</returns> public int GetDistance(GraphEdge edge) { return(GetDistance(edge.outside, edge.inside)); }
/// <summary> /// Uses Prim's algorithm to build an MST spanning the mstNodes. /// </summary> /// <param name="startFrom">A GraphNode to start from.</param> /// <returns>A list of GraphEdges forming the MST.</returns> public List <GraphEdge> Span(GraphNode startFrom) { /// With n nodes, we can have up to n (actually n-1) edges adjacent to each node. HeapPriorityQueue <GraphEdge> adjacentEdgeQueue = new HeapPriorityQueue <GraphEdge>(mstNodes.Count * mstNodes.Count); /// Removing all edges that satisfy a property (here a certain "outside" /// node) from the queue is not actually trivial, since you could only /// iterate over all entries (and you want to avoid that) if you don't /// have the references to the edges at hand. /// I guess this is the easiest way to do it... Dictionary <GraphNode, List <GraphEdge> > edgesLeadingToNode = new Dictionary <GraphNode, List <GraphEdge> >(); foreach (GraphNode node in mstNodes) { edgesLeadingToNode[node] = new List <GraphEdge>(); } // All nodes that are already included. HashSet <GraphNode> inMst = new HashSet <GraphNode>(); // All nodes that are not yet included. HashSet <GraphNode> toAdd = new HashSet <GraphNode>(mstNodes); List <GraphEdge> mstEdges = new List <GraphEdge>(); // Initialize the MST with the start nodes. inMst.Add(startFrom); toAdd.Remove(startFrom); edgesLeadingToNode[startFrom] = new List <GraphEdge>(); foreach (GraphNode otherNode in toAdd) { GraphEdge adjacentEdge = new GraphEdge(startFrom, otherNode); adjacentEdgeQueue.Enqueue(adjacentEdge, distances.GetDistance(adjacentEdge)); edgesLeadingToNode[otherNode].Add(adjacentEdge); } while (toAdd.Count > 0 && adjacentEdgeQueue.Count > 0) { GraphEdge shortestEdge = adjacentEdgeQueue.Dequeue(); mstEdges.Add(shortestEdge); GraphNode newIn = shortestEdge.outside; //if (inMst.Contains(newIn)) throw new Exception(); //if (!toAdd.Contains(newIn)) throw new Exception("No edge to this node should remain!"); inMst.Add(newIn); toAdd.Remove(newIn); // Remove all edges that are entirely inside the MST now. foreach (GraphEdge obsoleteEdge in edgesLeadingToNode[newIn]) { //if (!inMst.Contains(obsoleteEdge.inside)) throw new Exception("This edge's inside node is not inside"); adjacentEdgeQueue.Remove(obsoleteEdge); } edgesLeadingToNode.Remove(newIn); // Find all newly adjacent edges and enqueue them. foreach (GraphNode otherNode in toAdd) { GraphEdge adjacentEdge = new GraphEdge(newIn, otherNode); adjacentEdgeQueue.Enqueue(adjacentEdge, distances.GetDistance(adjacentEdge)); edgesLeadingToNode[otherNode].Add(adjacentEdge); } } if (toAdd.Count > 0) { throw new DistanceLookup.GraphNotConnectedException(); } this.SpanningEdges = mstEdges; _isSpanned = true; return(mstEdges); }
/// <summary> /// Retrieves the path distance from one node pf a graph edge to the other, /// or calculates it if it has not yet been found. /// </summary> /// <param name="edge">The graph edge.</param> /// <returns>The length of the graph edge (equals the amount of edges /// traversed).</returns> public int GetDistance(GraphEdge edge) { return GetDistance(edge.outside, edge.inside); }
/// <summary> /// Retrieves the shortest path from one node pf a graph edge to the other, /// or calculates it if it has not yet been found. /// </summary> /// <param name="edge">The graph edge.</param> /// <returns>The shortest path from outside to inside, not containing either and ordered from inside to outside.</returns> public ushort[] GetShortestPath(GraphEdge edge) { return GetShortestPath(edge.outside, edge.inside); }
/// <summary> /// Uses Prim's algorithm to build an MST spanning the mstNodes. /// </summary> /// <param name="startFrom">A GraphNode to start from.</param> /// <returns>A list of GraphEdges forming the MST.</returns> public List<GraphEdge> Span(GraphNode startFrom) { /// With n nodes, we can have up to n (actually n-1) edges adjacent to each node. HeapPriorityQueue<GraphEdge> adjacentEdgeQueue = new HeapPriorityQueue<GraphEdge>(mstNodes.Count * mstNodes.Count); /// Removing all edges that satisfy a property (here a certain "outside" /// node) from the queue is not actually trivial, since you could only /// iterate over all entries (and you want to avoid that) if you don't /// have the references to the edges at hand. /// I guess this is the easiest way to do it... Dictionary<GraphNode, List<GraphEdge>> edgesLeadingToNode = new Dictionary<GraphNode, List<GraphEdge>>(); foreach (GraphNode node in mstNodes) edgesLeadingToNode[node] = new List<GraphEdge>(); // All nodes that are already included. HashSet<GraphNode> inMst = new HashSet<GraphNode>(); // All nodes that are not yet included. HashSet<GraphNode> toAdd = new HashSet<GraphNode>(mstNodes); List<GraphEdge> mstEdges = new List<GraphEdge>(); // Initialize the MST with the start nodes. inMst.Add(startFrom); toAdd.Remove(startFrom); edgesLeadingToNode[startFrom] = new List<GraphEdge>(); foreach (GraphNode otherNode in toAdd) { GraphEdge adjacentEdge = new GraphEdge(startFrom, otherNode); adjacentEdgeQueue.Enqueue(adjacentEdge, distances.GetDistance(adjacentEdge)); edgesLeadingToNode[otherNode].Add(adjacentEdge); } while (toAdd.Count > 0 && adjacentEdgeQueue.Count > 0) { GraphEdge shortestEdge = adjacentEdgeQueue.Dequeue(); mstEdges.Add(shortestEdge); GraphNode newIn = shortestEdge.outside; //if (inMst.Contains(newIn)) throw new Exception(); //if (!toAdd.Contains(newIn)) throw new Exception("No edge to this node should remain!"); inMst.Add(newIn); toAdd.Remove(newIn); // Remove all edges that are entirely inside the MST now. foreach (GraphEdge obsoleteEdge in edgesLeadingToNode[newIn]) { //if (!inMst.Contains(obsoleteEdge.inside)) throw new Exception("This edge's inside node is not inside"); adjacentEdgeQueue.Remove(obsoleteEdge); } edgesLeadingToNode.Remove(newIn); // Find all newly adjacent edges and enqueue them. foreach (GraphNode otherNode in toAdd) { GraphEdge adjacentEdge = new GraphEdge(newIn, otherNode); adjacentEdgeQueue.Enqueue(adjacentEdge, distances.GetDistance(adjacentEdge)); edgesLeadingToNode[otherNode].Add(adjacentEdge); } } if (toAdd.Count > 0) throw new DistanceLookup.GraphNotConnectedException(); this.SpanningEdges = mstEdges; _isSpanned = true; return mstEdges; }