8. Graphs and Path

Objective: In this lecture, we'll examine the graph and show how to solve the shortest path problems. Topics include:

In this lecture unit, we show:

8.1 Definitions

8.2 Representation

8.3 The Graph Class Interface (I)

8.4 The Graph Class Interface (II)

class Graph
{
public:
   Graph() {}
   ~Graph();

   void addEdge(const string &sourceName,
                const string &destName, double cost);
   void printPath(const string &dsetName) const;
   void unweighted(const string &startName);
   void dijkstra(const string &startName);
   void acyclic(const string &startName);

private:
   Vextex *getVertex(const string &vertexName);
   void printPath(const Vertex &dest) const;
   void clearAll();

   typedef map<string, Vertex *, less<string>> vmap;

    // Copy semantics are disabled.
   Graph(const Graph &rhs) {}
   const Graph &operator=(const Graph &rhs)
   {
      return *this;
   }

   vmap vertexMap;
};

8.5 Implementation

Graph::~Graph()
{
   vmap::iterator itr;
   for (itr = vertexMap.begin(), itr != vertexMap.end(); ++itr)
   {
      delete (*itr).second;
   }
}

//
// If vertexName is not present, add it to vertexMap.
// In either case, return a pointer to the Vertex.
//
Vertex *Graph::getVertex(const string &vertexName)
{
   vmap::iterator itr = vertexMap.find(vertexName);
   if (itr == vertexMap.end())
   {
      Vertex *newv = new Vertex(vertexName);
      vertexMap[vertexName] = newv;
      return newv;
   }

   return (*itr).second;
}

//
// Add a new edge to the graph
//
void Graph::addEdge(const string &sourceName, const string &destName,
                    double cost)
{
   Vertex *v = getVertex(sourceName);
   Vertex *w = getVertex(destName);
   v->adj.push_back(Edge(w, cost));
}

//
// Initialize the vertex output info prior to
// running any shortest path algorithm.
//
void Graph::clearAll()
{
   vmap::iterator itr;
   for (itr = vertexMap.begin(); itr != vertexMap.end(); ++itr)
   {
      (*itr).second->reset();
   }
}

//
// Recursive routine to print shortest path to
// dest after running shortest path algorithm.
// The path is known to exist.
//
void Graph::printPath(const Vertex &dest) const
{
   if (dest.prev != NULL)
   {
      printPath(*dest.prev);
      cout << " To ";
   }

   cout << dest.name;
}

//
// Driver routine to handle unreachables and print
// total cost.  It calls recursive routine to print
// shortest path to destName after a shortest path
// algorithm has run.
//
void Graph::printPath(const string &destName) const
{
   vmap::const_iterator itr = vertexMap.find(destName);
   if (itr == vertexMap.end())
   {
      throw GraphException("Dest. vertex not found");
   }

   const Vertex &w = *(*itr).second;

   if (w.dist == INFINITY)
   {
      cout << destName << " is unreachable";
   }
   else
   {
      cout << "(cost is: " << w.dist << ") ";
      printPath(w);
   }

   cout << endl;
}

8.6 A Simple Program

//
// A simple main that reads the file given by arg[1] and
// then calls processRequest to compute shortest paths.
// Skip error checking in order to concentrate on the basics.
//
int main(int argc, char argv[])
{
   if (argc != 2)
   {
      cerr << "Usage: " << argv[0] << " graphfile"
           << endl;
      return 1;
   }

   ifstream inFile(argv[1]);

   if (!inFile)
   {
      cerr << "Cannot open " << argv[0] << endl;
      return 1;
   }

   cout << "Reading file... " << endl;
   string oneLine;

   // Read the edges; add them to g.
   Graph g;
   while (!getline(inFile, oneLine).eof())
   {
      string source, dest;
      double cost;
      istringstream st(oneLine);

      st >> source >> dest >> cost;

      if (st.fail())
      {
         cerr << "Bad line; " << oneLine << endl;
      }
      else
      {
         g.addEdge(source, dest, cost);
      }
   }

   cout << "File read" << endl <, endl;

   while (processRequest(cin, g))
     ;

  return 0;
}

//
// Porcess a request; return false if end of file.
//
bool processRequest(istream &in, Graph &g)
{
   string startName, destName;

   cout << "Enter start node: ";

   if (!(in >> startName))
   {
      return false;
   }

   cout << "Enter destination node: ";

   if (!(in >> destName))
   {
      return false;
   }

   try
   {
      g.unweighted(startName);
      g.printPath(destName);
   }
   catch
   {
      cerr << e.toString() << endl;
   }

   return true;
}  

8.7 Single-Source Shortest Path (Unweighed)

8.8 Single-Source Shortest Path (Positive-Weighed)