public void Ctor_ShouldInitializeAdjacencyLists() { var graph = new MixedGraph <int>(); Assert.NotNull(graph.AdjacencyLists); Assert.Empty(graph.AdjacencyLists); }
public void Ctor_ShouldInitializeAdjacencyListsWithVerticesAndEdges() { var vertices = new List <int> { 0, 1, 2, 3 }; var directedEdges = new List <Edge <int> > { new Edge <int>(0, 1), }; var undirectedEdges = new List <Edge <int> > { new Edge <int>(1, 2), new Edge <int>(0, 2) }; var expectedAdjacencyLists = new Dictionary <int, IReadOnlyList <int> >() { [0] = new List <int>() { 1, 2 }, [1] = new List <int>() { 2 }, [2] = new List <int>() { 1, 0 }, [3] = new List <int>(), }; var graph = new MixedGraph <int>(vertices, directedEdges, undirectedEdges); Assert.Equal(expectedAdjacencyLists, graph.AdjacencyLists); }
public void RemoveUndirectedEdge_ShouldRemoveConnectedVertexFromAdjacencyLists_WhenExistingKeysSpecified( MixedGraph <int> graph, int sourceToRemove, int destinationToRemove, Dictionary <int, IReadOnlyList <int> > expectedAdjacencyLists) { graph.RemoveUndirectedEdge(sourceToRemove, destinationToRemove); Assert.Equal(expectedAdjacencyLists, graph.AdjacencyLists); }
/// <summary> /// Starts depth-first search from an initial vertex, orienting each visited edge against its direction /// </summary> /// <param name="graph">Target graph</param> /// <param name="initialVertex">Initial vertex for DFS</param> /// <param name="passedVertices">Passed vertices queue</param> /// <returns>Modified (mixed) graph with each visited edge oriented against its direction</returns> private MixedGraph <TVertex> PrepareToSearchForEdgeDoubleConnectivityComponents(TGraph graph, TVertex initialVertex, out Queue <TVertex> passedVertices) { var graphClone = new MixedGraph <TVertex>( graph.Vertices, Enumerable.Empty <Edge <TVertex> >(), graph.ReducedEdges); var visitedVertices = new HashSet <TVertex>(new TVertex[] { initialVertex }, _verticesComparer); DfsGraphAndRemoveVisitedEdges(graphClone, initialVertex, visitedVertices); passedVertices = new Queue <TVertex>(visitedVertices); visitedVertices.Clear(); return(graphClone); }
public void Ctor_ShouldInitializeAdjacencyListsWithVertices() { var vertices = new List <int> { 0, 1, 2, 3 }; var graph = new MixedGraph <int>(vertices); Assert.Equal(vertices, graph.AdjacencyLists.Keys); Assert.All(graph.AdjacencyLists.Values, list => { Assert.Empty(list); }); }
/// <summary> /// Performs depth-first search on single graph's edge double-connectivity component and marks this component's vertices with component's id /// </summary> /// <param name="graph"></param> /// <param name="sourceVertex">Current vertex</param> /// <param name="visitedVertices">Visited vertices</param> /// <param name="edgeDoubleConnectivityComponents">Vertex to edge double-connectivity component mapping dictionary</param> /// <param name="curEdgeDoubleConnectivityComponentId">Current edge double-connectivity component's ID</param> private void DfsEdgeDoubleConnectivityComponent(MixedGraph <TVertex> graph, TVertex sourceVertex, ISet <TVertex> visitedVertices, IDictionary <TVertex, int?> edgeDoubleConnectivityComponents, int curEdgeDoubleConnectivityComponentId) { var notVisitedNeighbourVertices = graph.AdjacencyLists[sourceVertex].ToList(); foreach (var neighbourVertex in notVisitedNeighbourVertices) { if (!visitedVertices.Contains(neighbourVertex) && !edgeDoubleConnectivityComponents[neighbourVertex].HasValue) { visitedVertices.Add(neighbourVertex); edgeDoubleConnectivityComponents[neighbourVertex] = curEdgeDoubleConnectivityComponentId; DfsEdgeDoubleConnectivityComponent(graph, neighbourVertex, visitedVertices, edgeDoubleConnectivityComponents, curEdgeDoubleConnectivityComponentId); } } }
/// <summary> /// Performs depth-first search on graph, orienting each visited edge against its direction /// </summary> /// <param name="graph">Graph</param> /// <param name="sourceVertex">Current vertex</param> /// <param name="visitedVertices">Visited vertices</param> private void DfsGraphAndRemoveVisitedEdges(MixedGraph <TVertex> graph, TVertex sourceVertex, ISet <TVertex> visitedVertices) { var notVisitedNeighbourVertices = graph.AdjacencyLists[sourceVertex].ToList(); foreach (var neighbourVertex in notVisitedNeighbourVertices) { if (!visitedVertices.Contains(neighbourVertex)) { visitedVertices.Add(neighbourVertex); graph.RemoveDirectedEdge(sourceVertex, neighbourVertex); DfsGraphAndRemoveVisitedEdges(graph, neighbourVertex, visitedVertices); } } }
/// <summary> /// Finds edges that connect vertices of different edge double-connectivity components /// </summary> /// <param name="graphClone">Modified graph</param> /// <param name="edgeDoubleConnectivityComponents">Vertex to edge double-connectivity component mapping dictionary</param> /// <returns>Edges that connect vertices of different edge double-connectivity components</returns> private IEnumerable <Edge <TVertex> > FindBridges(MixedGraph <TVertex> graphClone, IDictionary <TVertex, int?> edgeDoubleConnectivityComponents) { var bridges = new List <Edge <TVertex> >(); foreach (var edge in graphClone.ReducedEdges) { var sourceComponentId = edgeDoubleConnectivityComponents[edge.Source]; var destinationComponentId = edgeDoubleConnectivityComponents[edge.Destination]; if (sourceComponentId != destinationComponentId) { bridges.Add(edge); } } return(bridges); }
/// <summary> /// Finds edge double-connectivity components for graph /// </summary> /// <param name="graphClone">Modified graph from previous stage</param> /// <param name="passedVertices">Passed vertices queue from previous stage</param> /// <returns>Dictionary where keys are vertices and values are edge double-connectivity component's id, which corresponding key vertex belongs to /// </returns> private IDictionary <TVertex, int?> FindEdgeDoubleConnectivityComponents(MixedGraph <TVertex> graphClone, Queue <TVertex> passedVertices) { var curEdgeDoubleConnectivityComponentId = 0; var edgeDoubleConnectivityComponents = graphClone.Vertices.ToDictionary(v => v, v => new int?()); while (passedVertices.Any()) { var curVertex = passedVertices.Dequeue(); if (edgeDoubleConnectivityComponents[curVertex].HasValue) { continue; } var visitedVertices = new HashSet <TVertex>(new TVertex[] { curVertex }, _verticesComparer); edgeDoubleConnectivityComponents[curVertex] = curEdgeDoubleConnectivityComponentId; DfsEdgeDoubleConnectivityComponent(graphClone, curVertex, visitedVertices, edgeDoubleConnectivityComponents, curEdgeDoubleConnectivityComponentId); curEdgeDoubleConnectivityComponentId++; } return(edgeDoubleConnectivityComponents); }
public void RemoveUndirectedEdge_ShouldThrowKeyNotFoundException_WhenNotExistingKeySpecified(MixedGraph <int> graph, int source, int destination) { Assert.Throws <KeyNotFoundException>(() => { graph.RemoveUndirectedEdge(source, destination); }); }
public void AddUndirectedEdge_ShouldThrowInvalidOperationException_WhenEdgeCreatesLoopOrMultipleEdge(MixedGraph <int> graph, int source, int destination) { Assert.Throws <InvalidOperationException>(() => { graph.AddUndirectedEdge(source, destination); }); }