/**
         * 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);
        }
Esempio n. 2
0
        /**
         * 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;
                }
            }
        }