/// <summary> /// Checks whether target graph can contain euler cycles /// </summary> /// <param name="graph">Target graph</param> private bool IsEulerGraph(TGraph graph) { var isAnyOddVertexDeg = graph.Vertices.Any(v => graph.GetVertexDeg(v) % 2 != 0); var connectedComponentsCount = _connectedComponentsCounter.Execute(graph); return(!isAnyOddVertexDeg && connectedComponentsCount < 2); }
public IEnumerable <Edge <TVertex> > Execute(TGraph graph) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (_connectedComponentsCounter.Execute(graph) > 1) { throw new InvalidOperationException("For Prim's algorithm graph cannot contain more than one connected component"); } if (!graph.Vertices.Any() || !graph.Weights.Any()) { return(Enumerable.Empty <Edge <TVertex> >()); } var initialConsideredVertices = new List <TVertex>() { graph.Vertices.First() }; // Vertices that are already included in spanning tree var consideredVertices = new HashSet <TVertex>(initialConsideredVertices, _verticesComparer); // Edges that are already included in spanning tree var spanningTreeEdges = new HashSet <Edge <TVertex> >(); while (graph.Vertices.Any(v => !consideredVertices.Contains(v))) { // For each considered vertex algorithm tries to find an edge of minimal weight // which is not included in spanning tree and doesn't create cycle var minWeight = Int32.MaxValue; var edgeToIncludeToSpanningTree = default(Edge <TVertex>); foreach (var sourceVertex in consideredVertices) { foreach (var destinationVertex in graph.AdjacencyLists[sourceVertex]) { var edge = new Edge <TVertex>(sourceVertex, destinationVertex); var weight = graph.Weights[edge]; if (IsEdgeValid(edge, consideredVertices, spanningTreeEdges) && weight < minWeight) { minWeight = weight; edgeToIncludeToSpanningTree = edge; } } } consideredVertices.Add(edgeToIncludeToSpanningTree.Destination); spanningTreeEdges.Add(edgeToIncludeToSpanningTree); } return(spanningTreeEdges); }
public IEnumerable <TVertex> Execute(TGraph graph, TVertex startVertex, TVertex endVertex) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (startVertex == null) { throw new ArgumentNullException(nameof(startVertex)); } if (endVertex == null) { throw new ArgumentNullException(nameof(endVertex)); } if (!graph.AdjacencyLists.ContainsKey(startVertex)) { throw new ArgumentException($"Start vertex = '{startVertex}' doesn't exist in graph"); } if (!graph.AdjacencyLists.ContainsKey(endVertex)) { throw new ArgumentException($"End vertex = '{endVertex}' doesn't exist in graph"); } if (_connectedComponentsCounter.Execute(graph) > 1) { throw new InvalidOperationException("For Lee algorithm graph should be highly connected"); } #region Algorithm description // The algorithm is using the "waves" term. // Wave is an integer value describing the number of edges needed to go from one vertex to another. // Start vertex has the wave value of 0. // The algorithm is divided into 2 stages: // 1. Calculating the waves // Each vertex (starting from initial one) is viewed. // For each its neighbour, that has unset wave value, wave is calculated as current vertex's wave + 1. // 2. Finding the path itself // To find the path from start to end vertex itself, graph traversal is started from end vertex, // passing through the vertices in which the value of the wave decreases by 1 until it reaches start vertex. #endregion var waves = CalculateWaves(graph, startVertex); var shortestPath = FindShortestPath(graph, startVertex, endVertex, waves); return(shortestPath); }
public IEnumerable <TVertex> Execute(TGraph graph) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (_connectedComponentsCounter.Execute(graph) > 1) { throw new InvalidOperationException("Target graph should be highly connected for searching articulation points in it"); } var foundArticulationPoints = new List <TVertex>(); // Cloning graph to save the original one var graphClone = new UndirectedGraph <TVertex>(graph.Vertices, graph.ReducedEdges) as TGraph; var graphVertices = graphClone.Vertices.ToList(); foreach (var vertex in graphVertices) { var sourceEdges = graphClone.Edges.Where(e => e.Source.CompareTo(vertex) == 0); var destinationEdges = graphClone.Edges.Where(e => e.Destination.CompareTo(vertex) == 0); graphClone.RemoveVertex(vertex); if (_connectedComponentsCounter.Execute(graphClone) > 1) { foundArticulationPoints.Add(vertex); } graphClone.AddVertex(vertex); foreach (var edge in sourceEdges) { graphClone.AddUndirectedEdge(edge.Source, edge.Destination); } } return(foundArticulationPoints); }
public IEnumerable <Edge <TVertex> > Execute(TGraph graph) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (_connectedComponentsCounter.Execute(graph) > 1) { throw new InvalidOperationException("Target graph should be highly connected for searching bridges in it"); } if (!graph.Vertices.Any()) { return(Enumerable.Empty <Edge <TVertex> >()); } #region Algorithm description // The algorithm is divided into 3 stages: // 1. Preparing graph for searching edge double-connectivity components. // Starts the depth-first search from an initial vertex. // In the process of walking along the edge [A -> B], it is "oriented" against the direction of movement. // When a new (unvisited) vertex is found, it is put at the end of the queue. // 2. Finding edge double-connectivity components. // The loop is started until the queue is empty. // The first vertex from the queue is retrieved, and if this vertex is unvisited, then depth-first search is started from this vertex. // In this case, the next component of the edge double-connectivity is formed. // As a result, when the queue is empty, components of edge double-connectivity will be formed. // 3. Finding those edges that connect vertices of different edge double-connectivity components. // Those edges are bridges. #endregion var initialVertex = graph.Vertices.First(); var graphClone = PrepareToSearchForEdgeDoubleConnectivityComponents(graph, initialVertex, out var passedVertices); var edgeDoubleConnectivityComponents = FindEdgeDoubleConnectivityComponents(graphClone, passedVertices); var bridges = FindBridges(graphClone, edgeDoubleConnectivityComponents); return(bridges); }
public IEnumerable <Edge <TVertex> > Execute(TGraph graph) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (_connectedComponentsCounter.Execute(graph) > 1) { throw new InvalidOperationException("For Kruskal's algorithm graph cannot contain more than one connected component"); } var edges = graph.ReducedEdges; var sortedEdgeWeightEntries = graph.Weights.Where(w => edges.Contains(w.Key)) .OrderBy(w => w.Value) .ToList(); var graphCopy = new UndirectedWeightedGraph <TVertex, int>(graph.Vertices) as TGraph; var spanningTreeEdges = new List <Edge <TVertex> >(); foreach (var edgeWeightEntry in sortedEdgeWeightEntries) { var edge = edgeWeightEntry.Key; var weight = edgeWeightEntry.Value; graphCopy.AddUndirectedEdge(edge.Source, edge.Destination, weight); if (IsAnyCycleDetected(graphCopy)) { graphCopy.RemoveUndirectedEdge(edge.Source, edge.Destination); } else { spanningTreeEdges.Add(new Edge <TVertex>(edge.Source, edge.Destination)); } } return(spanningTreeEdges); }