programming-examples/c++/Others/Graph2.cpp - Shortest path program not using STL.cpp
2019-11-15 12:59:38 +01:00

238 lines
5.6 KiB
C++

Graph2.cpp - Shortest path program not using STL
#include <iostream.h>
#include <fstream.h>
#include <limits.h>
#ifdef unix
#include <strstream.h>
#else
#include <strstrea.h> // <strstream.h> on UNIX machines
#endif
#include "mystring.h"
#include "SeparateChaining.h"
#include "LinkedList.h"
#include "QueueAr.h"
int INFINITY = INT_MAX;
struct Vertex
{
string name; // Vertex name
List<Vertex *> adj; // Adjacent vertices
int dist; // Cost
Vertex *path; // Previous vertex on shortest path
Vertex( const string & nm ) : name( nm )
{ reset( ); }
void reset( )
{ dist = INFINITY; path = NULL; }
};
struct MapEntry
{
string vertexName;
Vertex *storedVertex;
MapEntry( const string & name = "", Vertex * v = NULL )
: vertexName( name ), storedVertex( v ) { }
bool operator!=( const MapEntry & rhs ) const
{ return vertexName != rhs.vertexName; }
bool operator==( const MapEntry & rhs ) const
{ return vertexName == rhs.vertexName; }
};
int hash( const MapEntry & x, int tableSize )
{
return hash( x.vertexName, tableSize );
}
class Graph
{
public:
Graph( ) : vertexMap( MapEntry( ) ), numVertices( 0 ) { }
~Graph( );
void addEdge( const string & sourceName, const string & destName );
void printPath( const string & destName ) const;
void unweighted( const string & startName );
private:
Vertex * getVertex( const string & vertexName );
void printPath( const Vertex & dest ) const;
void clearAll( );
HashTable<MapEntry> vertexMap;
List<Vertex *> allVertices;
int numVertices;
const MapEntry ITEM_NOT_FOUND;
};
void Graph::addEdge( const string & sourceName, const string & destName )
{
Vertex * v = getVertex( sourceName );
Vertex * w = getVertex( destName );
v->adj.insert( w, v->adj.zeroth( ) );
}
void Graph::printPath( const string & destName ) const
{
const MapEntry & match = vertexMap.find( MapEntry( destName ) );
if( match == ITEM_NOT_FOUND )
{
cout << "Destination vertex not found" << endl;
return;
}
const Vertex & w = *match.storedVertex;
if( w.dist == INFINITY )
cout << destName << " is unreachable";
else
printPath( w );
cout << endl;
}
// If vertexName is not present, add it to vertexMap
// In either case, return the Vertex
Vertex * Graph::getVertex( const string & vertexName )
{
static MapEntry entry;
entry.vertexName = vertexName;
const MapEntry & match = vertexMap.find( entry );
if( match == ITEM_NOT_FOUND )
{
entry.storedVertex = new Vertex( vertexName );
allVertices.insert( entry.storedVertex, allVertices.zeroth( ) );
numVertices++;
vertexMap.insert( entry );
return entry.storedVertex;
}
return match.storedVertex;
}
void Graph::printPath( const Vertex & dest ) const
{
if( dest.path != NULL )
{
printPath( *dest.path );
cout << " to ";
}
cout << dest.name;
}
void Graph::clearAll( )
{
ListItr<Vertex *> itr;
for( itr = allVertices.first( ); !itr.isPastEnd( ); itr.advance( ) )
itr.retrieve( )->reset( );
}
Graph::~Graph( )
{
ListItr<Vertex *> itr;
for( itr = allVertices.first( ); !itr.isPastEnd( ); itr.advance( ) )
delete itr.retrieve( );
}
void Graph::unweighted( const string & startName )
{
clearAll( );
const MapEntry & match = vertexMap.find( MapEntry( startName ) );
if( match == ITEM_NOT_FOUND )
{
cout << startName << " is not a vertex in this graph" << endl;
return;
}
Vertex *start = match.storedVertex;
Queue<Vertex *> q( numVertices );
q.enqueue( start ); start->dist = 0;
while( !q.isEmpty( ) )
{
Vertex *v = q.dequeue( );
ListItr<Vertex *> itr;
for( itr = v->adj.first( ); !itr.isPastEnd( ); itr.advance( ) )
{
Vertex *w = itr.retrieve( );
if( w->dist == INFINITY )
{
w->dist = v->dist + 1;
w->path = v;
q.enqueue( w );
}
}
}
}
/**
* Process a request; return false if end of file.
*/
bool processRequest( istream & in, Graph & g )
{
string startName;
string destName;
cout << "Enter start node: ";
if( !( in >> startName ) )
return false;
cout << "Enter destination node: ";
if( !( in >> destName ) )
return false;
g.unweighted( startName );
g.printPath( destName );
return true;
}
/**
* A simple main that reads the file given by argv[1]
* and then calls processRequest to compute shortest paths.
* Skimpy error checking in order to concentrate on the basics.
*/
int main( int argc, char *argv[ ] )
{
Graph g;
if( argc != 2 )
{
cerr << "Usage: " << argv[ 0 ] << " graphfile" << endl;
return 1;
}
ifstream inFile( argv[ 1 ] );
if( !inFile )
{
cerr << "Cannot open " << argv[ 1 ] << endl;
return 1;
}
string oneLine;
// Read the words; add them to wordMap
while( getline( inFile, oneLine ) )
{
string source, dest;
istrstream st( (char *) oneLine.c_str( ) ); // Deprecated form of string streams
st >> source;
st >> dest;
g.addEdge( source, dest );
}
cout << "File read" << endl;
while( processRequest( cin, g ) )
;
return 0;
}