LAB 10: GRAPHS Exercise 1 Implement a Template Class Problem statement: Implement a new template class that is derived from the graph. The new class should permit both edges and vertices to have labels. Learning Objectives: The learner will be able to: Write a new template class derived from the graph template class that permits both edges and vertices to have labels. Exercise 2 Implement a Graph Function Problem statement: Implement a function with three arguments: a graph, a starting vertex number, and an ending vertex number. The function determines whether there is a directed path from the starting vertex to the ending vertex. Learning Objectives: The learner will be able to: Write a three-argument function to determine if a directed path exists from a starting vertex to an ending vertex. Equipment: Typical Computer Lab setup Components/Materials: Microsoft Visual C++ Classroom Configuration: N/A Lab Procedures: 1 Lab Handout for IT327 Data Structures Complete the following tasks: Exercise 1 1. Implement a new template class that is derived from the graph. 2. The new class should permit both edges and vertices to have labels. Complete the following tasks: Exercise 2 1. Implement a function with three arguments: a graph, a starting vertex number, and an ending vertex number. 2. The function determines whether there is a directed path from the starting vertex to the ending vertex. Validation/Evaluation Answers to Lab Exercises Solutions to Lab Exercises can be found at the Curriculum Knowledge Network (CKN) section of the ITT Technical Institute Employee Portal, http://myportal.itttech.edu. The solutions are also listed below. Exercise 1 // FILE: graph.h (part of the namespace main_savitch_15) // From Chapter 15 of Data Structures and Other Objects (Second Edition) // ________________________________________________________________________ // // This file has been modified to work with Microsoft Visual C++ 6.0, // as described in www.cs.colorado.edu/~main/vc6.html // ________________________________________________________________________ // // TEMPLATE CLASS PROVIDED: graph<Item> (a class for labeled graphs) // The vertices of an n-vertex graph are numbered from zero to n-1. Each vertex // has a label of type Item. It may be any of the C++ built-in types (int, // char, etc.), or any class with a default constructor and an assignment // operator. The graph may not have multiple edges. // // MEMBER CONSTANTS for the graph<Item> template class: // static const size_t MAXIMUM = ______ // graph::MAXIMUM is the maximum number of vertices that a graph can have. // // CONSTRUCTOR for the graph<Item> template class: // graph( ) // Postcondition: The graph has been initialized with no vertices and no edges. // // MODIFICATION MEMBER FUNCTIONS for the graph<Item> template class: // void add_vertex(const Item& label) 2 Lab Handout for IT327 Data Structures // Precondition: size( ) < MAXIMUM. // Postcondition: The size of the graph has been increased by adding one new // vertex. This new vertex has the specified label and no edges. // // void add_edge(size_t source, size_t target) // Precondition: (source < size( )) and (target < size( )). // Postcondition: The graph has all the edges that it originally had, and it // also has another edge from the specified source to the specified target. // (If this edge was already present, then the graph is unchanged.) // // void remove_edge(size_t soure, size_t target) // Precondition: (source < size( )) and (target < size( )). // Postcondition: The graph has all the edges that it originally had except // for the edge from the specified source to the specified target. (If this // edge was not originally present, then the graph is unchanged.) // // Item& operator [ ] (size_t vertex) // Precondition: vertex < size( ). // Postcondition: The return value is a reference to the label of the // specified vertex. // // CONSTANT MEMBER FUNCTIONS for the graph<Item> template class: // size_t size( ) const // Postcondition: The return value is the number of vertices in the graph. // // bool is_edge(size_t source, size_t target) const // Precondition: (source < size( )) and (target < size( )). // Postcondition: The return value is true if the graph has an edge from // source to target. Otherwise the return value is false. // // set<size_t> neighbors(size_t vertex) const // Precondition: (vertex < size( )). // Postcondition: The return value is a set that contains all the vertex // numbers of vertices that are the target of an edge whose source is at // the specified vertex. // // Item operator [ ] (size_t vertex) const // Precondition: vertex < size( ). // Postcondition: The return value is a reference to the label of the // specified vertex. // NOTE: This function differs from the other operator [ ] because its // return value is simply a copy of the Item (rather than a reference of // type Item&). Since this function returns only a copy of the Item, it is // a const member function. // // VALUE SEMANTICS for the graph<Item> template class: 3 Lab Handout for IT327 Data Structures // Assignments and the copy constructor may be used with graph<Item> objects. #ifndef MAIN_SAVITCH_GRAPH_H #define MAIN_SAVITCH_GRAPH_H #include <cstdlib> // Provides size_t #include <set> // Provides set namespace main_savitch_15 { template <class Item> class graph { public: // MEMBER CONSTANTS // * For VC++ 6.0 we are using size_t instead of std::size_t. And we // * have defined CAPACITY using an enum instead of a static member // * constant. See www.cs.colorado.edu/~main/vc6.html for details. enum { MAXIMUM = 20 }; // CONSTRUCTOR graph( ) { many_vertices = 0; } // MODIFICATION MEMBER FUNCTIONS void add_vertex(const Item& label); void add_edge(size_t source, size_t target); void remove_edge(size_t source, size_t target); Item& operator [ ] (size_t vertex); // CONSTANT MEMBER FUNCTIONS size_t size( ) const { return many_vertices; } bool is_edge(size_t source, size_t target) const; std::set<size_t> neighbors(size_t vertex) const; Item operator[ ] (size_t vertex) const; private: bool edges[MAXIMUM][MAXIMUM]; Item labels[MAXIMUM]; size_t many_vertices; }; } #include "graph.template" // Include the implementation. #endif // FILE: graph.template (part of the namespace main_savitch_15) // From Chapter 15 of Data Structures and Other Objects (Second Edition) // ________________________________________________________________________ // // This file has been modified to work with Microsoft Visual C++ 6.0, 4 Lab Handout for IT327 Data Structures // as described in www.cs.colorado.edu/~main/vc6.html // ________________________________________________________________________ // // TEMPLATE CLASS IMPLEMENTED: graph<Item> (See graph.h for documentation.) // This file is included in the header file and not compiled separately. // INVARIANT for the graph class: // 1. The number of vertices in the graph is stored in the member variable // many_vertices. // 1. These vertices are numbered from 0 to many_vertices-1. // 2. edges is the adjacency matrix for the graph (with true in edges[i][j] // to indicate an edge from vertex i to vertex j). // 3. For each i < many_vertices, labels[i] is the label of vertex i. #include <cassert> // Provides assert #include <cstdlib> // Provides size_t #include <set> // Provides set namespace main_savitch_15 { /* Not needed for VC++ template <class Item> const std::size_t graph<Item>::MAXIMUM; */ template <class Item> void graph<Item>::add_edge(size_t source, size_t target) // Library facilities used: cassert, cstdlib { assert(source < size( )); assert(target < size( )); edges[source][target] = true; } template <class Item> void graph<Item>::add_vertex(const Item& label) // Library facilities used: cassert, cstdlib { size_t new_vertex_number; size_t other_number; assert(size( ) < MAXIMUM); new_vertex_number = many_vertices; many_vertices++; for (other_number = 0; other_number < many_vertices; ++other_number) 5 Lab Handout for IT327 Data Structures { edges[other_number][new_vertex_number] = false; edges[new_vertex_number][other_number] = false; } labels[new_vertex_number] = label; } template <class Item> bool graph<Item>::is_edge(size_t source, size_t target) const // Library facilities used: cassert, cstdlib { assert(source < size( )); assert(target < size( )); return edges[source][target]; } template <class Item> Item& graph<Item>::operator[ ] (size_t vertex) // Library facilities used: cassert, cstdlib { assert(vertex < size( )); return labels[vertex]; // Returns a reference to the label } template <class Item> Item graph<Item>::operator[ ] (size_t vertex) const // Library facilities used: cassert, cstdlib { assert(vertex < size( )); return labels[vertex]; // Returns only a copy of the label } template <class Item> std::set<size_t> graph<Item>::neighbors(size_t vertex) const // Library facilities used: cassert, cstdlib, set { std::set<size_t> answer; size_t i; assert(vertex < size( )); for (i = 0; i < size( ); ++i) { if (edges[vertex][i]) answer.insert(i); } return answer; } template <class Item> 6 Lab Handout for IT327 Data Structures void graph<Item>::remove_edge(size_t source, size_t target) // Library facilities used: cassert, cstdlib { assert(source < size( )); assert(target < size( )); edges[source][target] = false; } } 7 Lab Handout for IT327 Data Structures Exercise 2 // FILE: searches.h (part of namespace main_savitch_15) // This file provides three template functions for searching graphs // from the graph template class of graph.h // // template <class Process, class Item, class SizeType> // void rec_dfs(Process f, graph<Item>& g, SizeType v, bool marked[]) // Precondition: g is a labeled graph that is being traversed by a // depth-first search. For each vertex x, marked[x] is true if x has // already been visited by this search, otherwise marked[x] is false. // The vertex v is an unmakred vertex that the search has just arrived at. // Postcondition: the depth-first search of g has been continued // through vertex v and beyond to all the vertices that can be reached // from v via a path of unmarked vertices. The function f has been // applied to the labe of each vertex visited by the search, and each // such vertex x has also been marked by setting marked[x] to true. // // template <class Process, class Item, class SizeType> // void depth_first(Process f, graph<Item>& g, SizeType start) // Precondion: start is a vertex number of the labeled graph g. // Postcondition: A depth-first search of g has been executed, // starting at the start vertex. The function f has been applied to the // label of each vertex visited by the search. // // template <class Process, class Item, class SizeType> // void breadth_first(Process f, graph<Item>& g, SizeType start) // Precondition: start is a vertex number of the labeled graph g. // Postcondition: A breadth-first search of g has been executed, // starting at the start vertex. The function f has been applied to the // label of each vertex visited by the search. #ifndef SEARCHES_H #define SEARCHES_H #include "graph.h" namespace main_savitch_15 { template <class Process, class Item, class SizeType> void rec_dfs(Process f, graph<Item>& g, SizeType v, bool marked[]); template <class Process, class Item, class SizeType> void depth_first(Process f, graph<Item>& g, SizeType start); template <class Process, class Item, class SizeType> void breadth_first(Process f, graph<Item>& g, SizeType start); } 8 Lab Handout for IT327 Data Structures #include "searches.template" // Include the implementation. #endif // FILE: searches.template // From Chapter 15 of Data Structures and Other Objects (Second Edition) // ________________________________________________________________________ // // This file has been modified to work with Microsoft Visual C++ 6.0, // as described in www.cs.colorado.edu/~main/vc6.html // ________________________________________________________________________ // // TEMPLATE FUNCTIONS IMPLEMENTED: rec_dfs, depth_first, and breadth_first. // Please see searches.h for documentation of these functions. // This file is included at the bottom of searches.h, and should not be // separately compiled. #include <algorithm> #include <cassert> #include <cstdlib> #include <queue> #include <set> #include "graph.h" namespace main_savitch_15 { template <class Process, class Item, class SizeType> void rec_dfs(Process f, graph<Item>& g, SizeType v, bool marked[]) // Precondition: g is a labeled graph that is being traversed by a // depth-first search. For each vertex x, marked[x] is true if x has // already been visited by this search, otherwise marked[x] is false. // The vertex v is an unmakred vertex that the search has just arrived at. // Postcondition: the depth-first search of g has been continued // through vertex v and beyond to all the vertices that can be reached // from v via a path of unmarked vertices. The function f has been // applied to the labe of each vertex visited by the search, and each // such vertex x has also been marked by setting marked[x] to true. // Library facilities used: cstdlib, graph.h, set { std::set<size_t> connections = g.neighbors(v); std::set<size_t>::iterator it; marked[v] = true; // Mark vertex v f(g[v]); // Process the label of vertex v with the function f 9 Lab Handout for IT327 Data Structures // Traverse all the neighbors, looking for unmarked vertices: for (it = connections.begin( ); it != connections.end( ); ++it) { if (!marked[*it]) rec_dfs(f, g, *it, marked); } } template <class Process, class Item, class SizeType> void depth_first(Process f, graph<Item>& g, SizeType start) // Precondion: start is a vertex number of the labeled graph g. // Postcondition: A depth-first search of g has been executed, // starting at the start vertex. The function f has been applied to the // label of each vertex visited by the search. // Library facilities used: algorithm, cassert, graph.h { bool marked[g.MAXIMUM]; assert(start < g.size( )); std::fill_n(marked, g.size( ), false); rec_dfs(f, g, start, marked); } template <class Process, class Item, class SizeType> void breadth_first(Process f, graph<Item>& g, SizeType start) // Precondition: start is a vertex number of the labeled graph g. // Postcondition: A breadth-first search of g has been executed, // starting at the start vertex. The function f has been applied to the // label of each vertex visited by the search. // Library facilities used: algorithm, cassert, cstdlib, graph.h, queue { bool marked[g.MAXIMUM]; std::set<size_t> connections; std::set<size_t>::iterator it; std::queue<size_t> vertex_queue; assert(start < g.size( )); std::fill_n(marked, g.size( ), false); marked[start] = true; f(g[start]); vertex_queue.push(start); do { connections = g.neighbors(vertex_queue.front( )); vertex_queue.pop( ); // Mark and process the unmarked neighbors, // and place them in the queue. 10 Lab Handout for IT327 Data Structures for (it = connections.begin( ); it != connections.end( ); ++it) { if (!marked[*it]) { marked[*it] = true; f(g[*it]); vertex_queue.push(*it); } } } while (!vertex_queue.empty( )); } } 11 Lab Handout for IT327 Data Structures