Nyhoff, ADTs, Data Structures and Problem
Solving with C++, Second Edition,
© 2005 Pearson Education, Inc. All rights reserved. 0-13-140909-3
Adjacency-List Class Template |
#include <list>
#include <vector>
template <typename DataType>
class Digraph
{
public:
/*** Functions for digraph operations ***/
private:
/*** Class for data and adjacency lists ***/
class VertexInfo
{
public:
DataType data;
list <int> adjacencyList;
};
/*** Data Members ***/
vector <VertexInfo> v;
);
|
Figure 16.1 Digraph Class Template |
/*--- Digraph.h ------------------------------------------------------------
Header file for Digraph Class Template
-------------------------------------------------------------------------*/
#include <list>
#include <vector>
#include <queue>
#include <iostream>
#include <fstream>
template <typename DataType>
class Digraph
{
public:
/***** Function Members *****/
DataType data(int k) const;
/*-----------------------------------------------------------------------
Retrieve data value in a given vertex.
Precondition: k is the number of a vertex.
Postcondition: Data value stored in vertex k is returned.
-----------------------------------------------------------------------*/
void read(ifstream & inStream);
/*-----------------------------------------------------------------------
Input operation.
Precondition: ifstream inStream is open. The lines in the file to
which it is connected are organized so that the data item in a
vertex is on one line and on the next line is the number of
vertices adjacent to it followed by a list of of these vertices.
Postcondition: The adjacency list representation of this digraph
has been stored in myAdjacencyLists.
-----------------------------------------------------------------------*/
void display(ostream & out);
/*-----------------------------------------------------------------------
Output operation.
Precondition: ostream out is open.
Postcondition: Each vertexb and its adjacency list have
been output to out.
-----------------------------------------------------------------------*/
void depthFirstSearch(int start);
/*-----------------------------------------------------------------------
Depth first search of digraph via depthFirstSearchAux(), starting
at vertex start.
Precondition: start is a vertex.
Postcondition: All elements of unvisited are initialized to true.
-----------------------------------------------------------------------*/
void depthFirstSearchAux(int start, vector<bool> & unvisited);
/*-----------------------------------------------------------------------
Recursive depth first search of digraph, starting at vertex start.
Precondition: start is a vertex; unvisited[i] is true if vertex i has
not yet been visited, and is false otherwise.
Postcondition: Vector unvisited has been updated.
-----------------------------------------------------------------------*/
vector<int> shortestPath(int start, int destination);
/*-----------------------------------------------------------------------
Find a shortest path in the digraph from vertex start to vertex
destination.
Precondition: start and destination are vertices.
Postcondition: A vector of vertices along the shortest path from
start to destination is returned.
-----------------------------------------------------------------------*/
private:
/***** "Head nodes" of adjacency lists *****/
class VertexInfo
{
public:
DataType data;
list<int> adjacencyList;
};
/***** Data member *****/
vector<VertexInfo> myAdjacencyLists;
}; // end of Digraph class template declaration
//--- Definition of data()
template <typename DataType>
inline DataType Digraph<DataType>::data(int k) const
{
return myAdjacencyLists[k].data;
}
//--- Definition of read()
template <typename DataType>
void Digraph<DataType>::read(ifstream & inStream)
{
Digraph<DataType>::VertexInfo vi;
int n, // number of vertices adjacent to some vertex
vertex; // the number of a vertex
// Put a garbage 0-th value so indices start with 1, as is customary
myAdjacencyLists.push_back(vi);
// Construct adjacency list representation
for (;;)
{
inStream >> vi.data;
if (inStream.eof()) break;
inStream >> n;
list<int> adjList; // construct empty list
for (int i = 1; i <= n; i++)
{
inStream >> vertex;
adjList.push_back(vertex);
}
vi.adjacencyList = adjList;
myAdjacencyLists.push_back(vi);
}
}
//--- Definition of display()
template <typename DataType>
void Digraph<DataType>::display(ostream & out)
{
out << "Adjacency-List Representation: \n";
for (int i = 1; i < myAdjacencyLists.size(); i++)
{
out << i << ": " << myAdjacencyLists[i].data << "--";
for (list<int>::iterator
it = myAdjacencyLists[i].adjacencyList.begin();
it != myAdjacencyLists[i].adjacencyList.end(); it++)
out << *it << " ";
out << endl;
}
}
//-- Definitions of depthFirstSearch() and depthFirstSearchAux()
template <typename DataType>
void Digraph<DataType>::depthFirstSearch(int start)
{
vector<bool> unvisited(myAdjacencyLists.size(), true);
depthFirstSearchAux(start, unvisited);
}
template <typename DataType>
void Digraph<DataType>::depthFirstSearchAux(
int start, vector<bool> & unvisited)
{
// Add statements here to process myAdjacencyLists[start].data
cout << myAdjacencyLists[start].data << endl;
unvisited[start] = false;
// Traverse its adjacency list, performing depth-first
// searches from each unvisited vertex in it.
for (list<int>::iterator
it = myAdjacencyLists[start].adjacencyList.begin();
it != myAdjacencyLists[start].adjacencyList.end(); it++)
// check if current vertex has been visited
if (unvisited[*it])
// start DFS from new node
depthFirstSearchAux(*it, unvisited);
}
//--- Definition of shortestPath()
template<typename DataType>
vector<int> Digraph<DataType>::shortestPath(int start, int destination)
{
int n = myAdjacencyLists.size(); // number of vertices (#ed from 1)
vector<int> distLabel(n,-1), // distance labels for vertices, all
// marked as unvisited (-1)
predLabel(n); // predecessor labels for vertices
// Perform breadth first search from start to find destination,
// labeling vertices with distances from start as we go.
distLabel[start] = 0;
int distance = 0, // distance from start vertex
vertex; // a vertex
queue<int> vertexQueue; // queue of vertices
vertexQueue.push(start);
while (distLabel[destination] < 0 && !vertexQueue.empty())
{
vertex = vertexQueue.front();
vertexQueue.pop();
if (distLabel[vertex] > distance)
distance++;
for (list<int>::iterator
it = myAdjacencyLists[vertex].adjacencyList.begin();
it != myAdjacencyLists[vertex].adjacencyList.end(); it++)
if (distLabel[*it] < 0)
{
distLabel[*it] = distance + 1;
predLabel[*it] = vertex;
vertexQueue.push(*it);
}
}
distance++;
// Now reconstruct the shortest path if there is one
vector<int> path(distance+1);
if (distLabel[destination] < 0)
cout << "Destination not reachable from start vertex\n";
else
{
path[distance] = destination;
for (int k = distance - 1; k >= 0; k--)
path[k] = predLabel[path[k+1]];
}
return path;
}
|
Figure 16.2 Shortest Paths in a Network |
/*-------------------------------------------------------------------------
Program to find the most direct route in an airline network from a given
start city to a given destination city. A digraph represented by its
adjacency-list implementation is used for the network, and the
information needed to construct it is read from networkFile.
-------------------------------------------------------------------------*/
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <vector>
using namespace std;
#include "Digraph.h"
int main()
{
cout << "Enter name of network file: ";
string networkFile;
cin >> networkFile;
ifstream inFile(networkFile.data());
if (!inFile.is_open())
{
cerr << "*** Cannot open " << networkFile << " ***\n";
exit(-1);
}
Digraph<string> d;
d.read(inFile);
cout << "The Digraph's ";
d.display(cout);
cout << endl;
int start, destination;
char response;
do
{
cout << "Number of start city? ";
cin >> start;
cout << "Number of destination? ";
cin >> destination;
vector<int> path = d.shortestPath(start, destination);
cout << "Shortest path is:\n";
for (int k = 0; k < path.size() - 1; k++)
{
cout << setw(3) << path[k] << ' ' << d.data(path[k]) << endl;
cout << " |\n"
" v\n";
}
cout << setw(3) << destination << ' ' << d.data(destination) << endl;
cout << "\nMore (Y or N)?";
cin >> response;
}
while (response == 'y' || response == 'Y');
}
|
Figure 16.4 Graph Class Template |
/*--- Graph.h -------------------------------------------------------------
Header file for Graph Class Template
-------------------------------------------------------------------------*/
#include <vector>
#include <iostream>
template <typename DataType>
class Graph
{
public:
/***** Function Members *****/
DataType data(int k) const;
/*-----------------------------------------------------------------------
Retrieve data value in a given vertex.
Precondition: k is the number of a vertex.
Postcondition: Data value stored in vertex #k is returned.
-----------------------------------------------------------------------*/
void read(istream & in, int numVertices, int numEdges);
/*-----------------------------------------------------------------------
Input operation.
Precondition: istream in is open; numVertices and numEdges are the
number of vertices and edges in the graph, respectively.
Postcondition: The vertices and edges of the graph have been read
from in and the edge-list representation of this graph stored
in myEdgeLists.
-----------------------------------------------------------------------*/
void depthFirstSearch(int start, vector<bool> & unvisited);
/*-----------------------------------------------------------------------
Depth first search of graph via depthFirstSearchAux(), starting
at vertex start.
Precondition: start is a vertex.
Postcondition: All elements of unvisited are initialized to true.
-----------------------------------------------------------------------*/
void depthFirstSearchAux(int start, vector<bool> & unvisited);
/*-----------------------------------------------------------------------
Recursive depth first search of graph, starting at vertex start.
Precondition: start is a vertex; unvisited[i] is true if vertex i has
not yet been visited, and is false otherwise.
Postcondition: Vector unvisited has been updated.
-----------------------------------------------------------------------*/
bool isConnected();
/*-----------------------------------------------------------------------
Check if graph is connected.
Precondition: None.
Postcondition: True is returned if graph is connected, false if not.
-----------------------------------------------------------------------*/
private:
/***** Edge Nodes *****/
class EdgeNode
{
public:
int vertex[3]; // Use 1 and 2 for indices
EdgeNode * link[3]; // as is customary
};
typedef EdgeNode * EdgePointer;
/***** "Head nodes" of edge lists *****/
class VertexInfo
{
public:
DataType data; // data value in vertex
EdgePointer first; // pointer to first edge node
};
/***** Data Members *****/
vector<VertexInfo> myEdgeLists;
}; // end of Graph class template declaration
//--- Definition of data()
template <typename DataType>
inline DataType Graph<DataType>::data(int k) const
{
return myEdgeLists[k].data;
}
//--- Definition of read()
template <typename DataType>
void Graph<DataType>::read(istream & in, int numVertices, int numEdges)
{
Graph<DataType>::VertexInfo vi;
// Put a garbage 0-th value so indices start with 1, as is customary
myEdgeLists.push_back(vi);
// Create "head nodes"
cout << "Enter label of vertex:\n";
for (int i = 1; i <= numVertices; i++)
{
cout << " " << i << ": ";
in >> vi.data;
vi.first = 0;
myEdgeLists.push_back(vi);
}
int endpoint; // endpoint of an edge
// Create edge lists
cout << "Enter endpoints of edge\n";
for (int i = 1; i <= numEdges; i++)
{
cout << " " << i << ": ";
EdgePointer newPtr = new EdgeNode;
for (int j = 1; j <= 2; j++)
{
in >> endpoint;
// insert new edge node at beginning
// of edge list for endpoint
newPtr->vertex[j] = endpoint;
newPtr->link[j] = myEdgeLists[endpoint].first;
myEdgeLists[endpoint].first = newPtr;
}
}
}
/*--- Utility function to check if all nodes have been visited.
Precondition: unvisited tells which nodes have not been
visited
Postcondition: true is returned if all vertices, false if not.
---------------------------------------------------------------*/
bool anyLeft(const vector<bool> & unvisited)
{
for (int i = 1; i < unvisited.size(); i++)
if (unvisited[i])
return true;
return false;
}
//-- Definition of depthFirstSearch()
template <typename DataType>
void Graph<DataType>::depthFirstSearch(int start, vector<bool> & unvisited)
{
// --- Insert statements here to process visited node
// Mark start visited, and initialize pointer
// to its first edge node to begin DFS.
unvisited[start] = false;
Graph<DataType>::EdgePointer ptr = myEdgeLists[start].first;
while(anyLeft(unvisited) && ptr != 0)
{
// Determine which end of edge is start
int startEnd = 1,
otherEnd = 2;
if (ptr->vertex[1] != start)
{ startEnd = 2; otherEnd = 1;}
// Start new (recursive) DFS from vertex at other end
// if it hasn't already been visited
int newStart = ptr->vertex[otherEnd];
if (unvisited[newStart])
depthFirstSearch(newStart, unvisited);
// Move to next edge node
ptr = ptr->link[startEnd];
}
}
//-- Definition of isConnected()
template <typename DataType>
bool Graph<DataType>::isConnected()
{
vector<bool> unvisited(myEdgeLists.size(), true);
depthFirstSearch(1, unvisited);
return !anyLeft(unvisited);
}
|
Figure 16.5 Graph Connectedness |
/*-------------------------------------------------------------------------
Program to determine if a graph is connected. If the graph is not
connected, a list of unreachable vertices from the start vertex is
provided to the user.
------------------------------------------------------------------------*/
#include <iostream>
using namespace std;
#include "Graph.h"
int main()
{
int numVertices, // number of vertices in the graph
numEdges; // " " edges " " "
cout << "Enter number of vertices and number of edges in graph: ";
cin >> numVertices >> numEdges;
Graph<char> g;
g.read(cin, numVertices, numEdges);
cout << "Graph is ";
if (g.isConnected())
cout << "connected.\n";
else
{
cout << "not connected.\n"
"Would you like to see which vertices are not\n"
"reachable from vertex 1 ("
<< g.data(1) << ") -- (Y or N)? ";
char response;
cin >> response;
if (response == 'y' || response == 'Y')
{
cout << "They are the following: \n";
vector<bool> unreachable(numVertices + 1, true);
g.depthFirstSearch(1, unreachable);
for (int i = 1; i < unreachable.size(); i++)
if (unreachable[i])
cout << "Vertex " << i << " (" << g.data(i) << ")\n";
}
cout << endl;
}
}
|