/** * Finds a minimum spanning tree in the graph. * * The MST is found using a modifed DFS algorithm. The only difference * to the algorithm implemented by DepthFirstSearch() method, is that * here we record the edges that were crossed throughout the algorithm. * These edges make up the MST at the end of the DFS search. * * @param start_index The index of the vertex where search starts at. * @param mst Unweighted tree instance that will become * an MST in this method. The MST instance must * already contain all the original's graph * vertices. * * @return The unweighted graph instance representing the MST. Note * that NULL is returned if there is no path from the vertex at * start_index to one or more vertices in the graph. * * @throws ArgumentException exception if start_index is negative * or greater-or-equal to the number of vertices in the graph. */ protected IUnweightedGraph <VertexT> FindMinimumSpanningTree( int start_index, IUnweightedGraph <VertexT> mst) { if (start_index < 0 || start_index >= Size) { throw new ArgumentException(); } // Tracks the visited vertices so that we don't visit the same // vertex multiple times BitArray visited = new BitArray(Size, false); // After they are visited, the vertices are pushed to the stack // so that search can be continued at them at later time StackViaLinkedList <int> stack = new StackViaLinkedList <int>(); // Push the start vertex to the queue and mark it as visited. stack.Push(start_index); visited[start_index] = true; int added_edges_count = 0; // The column of the adjacency matrix where the search for adjacent // vertices needs to start from. This is set to stack.Pop() + 1 so // that we don't re-scan the entire row of the adjacency matrix // when we continue looking at the adjacent vertices of the vertex // that was pushed to the stack before int column = 0; while (!stack.IsEmpty()) { for (; column < Size; ++column) { if (Edges.EdgeExists(stack.Peak(), column) && !visited[column]) { // Found an unvisited adjacent vertex. Add an edge between // this vertex and the vertex at the top of the stack. // Note that if this is an undirected graph, the AddEdge // method bellow will also add an edge in the opposite // direction. mst.AddEdge(stack.Peak(), column); // Mark it as visited and push it to the stack stack.Push(column); visited[column] = true; ++added_edges_count; // Reset the column to 0 so that the adjacency matrix row // corresponding to unvisited vertex is scanned from the // beginning column = 0; // Break the the loop as we need to look at the adjecent // vertices of the new vertex at the top of the stack next break; } } if (column == Size) { // We've found no unvisited adjecent vertices of the vertex // at the top of the stack. Pop it off the stack so the next // iteration will look at other adjacent vertices of the // new top of the stack. Note that column is set to // stack.Pop() + 1 so we start scanning that vertex's // adjacency matrix row from where we left off column = stack.Pop() + 1; } } // The MST must consists of Size - 1 edges. If this is not the // case, the graph is disconnected and MST doesn't exist (in // which case NULL is returned) return(added_edges_count == Size - 1 ? mst : null); }
/** * Uses DFS to find all vertices connected to the vertex at the start_index. * * TODO: describe the algorithm * * This is an iterator method that yields the control to the * caller each time a new vertex is visited. * * @param start_index The vertex index where DFS is started from. * * @return An iterator interface type used to iterate over the vertices * produced by the DFS algorithm. * * @note The method returns a vertex index and not the vertex itself. * The caller can use GetVertex() to get access the vertex. * * @throws @throws ArgumentException exception if vertex_index is negative * or greater-or-equal to the number of vertices in the graph. */ public IEnumerable <int> DepthFirstSearch(int start_index) { if (start_index < 0 || start_index >= Size) { throw new ArgumentException(); } // Tracks which vertices are visited during the DFS search BitArray visited_vertices = new BitArray(Size, false); // Once visited, vertex indicies are pushed onto the stack StackViaLinkedList <int> stack = new StackViaLinkedList <int>(); // Visit the starting vertex yield return(start_index); stack.Push(start_index); visited_vertices[start_index] = true; // The adjacency matrix column from which to start checking for // adjacent vertices of the vertex at the top of the stack. int column = 0; // DFS algorithm is done once stack becomes empty while (!stack.IsEmpty()) { // Scan the adjacency matrix row corresponding to the vertex // at the top of the stack for (; column < Size; ++column) { if (Edges.EdgeExists(stack.Peak(), column) && !visited_vertices[column]) { // Found an adjecent vertex that hasn't been visited yet. // Visit it and push it to the stack yield return(column); stack.Push(column); visited_vertices[column] = true; break; } } if (column == Size) { // This means that the for-loop didn't find an unvisited // adjecent vertex of the vertex at the stack's top. Pop // the stack and assign the (stack.Pop() + 1) to the column // variable. This make sure that the next iteration scans // the row corresponding to the vertex at the top of the // stack from the index that it reached earlier, instead // of re-scaning the entire row. column = stack.Pop() + 1; } else { // The previous for-loop found an unvisited adjecent vertex // of the vertex at the top of the stack. Reset column to // 0 as the next iteration needs to scan the row that // corresponds to the new stack's top from the start. column = 0; } } }