Transcript ppt
Using a Directed Graph
Drozdek Chapter 8
1
Objectives
You will be able to
Understand and use a C++ ADT for a
directed graph.
Describe and implement an algorithm for
finding the shortest path between two
nodes in a directed graph.
2
New Project
3
New Project
4
Implementation of a Directed Graph ADT
Download to project directory:
http://www.cse.usf.edu/~turnerr/Data_Structures/Downloads/
2011_04_25_Directed_Graphs/
Digraph.h
shortest_path.cpp
NetworkFile.txt
Delete .txt from the .h and .cpp files
Add the .h and .cpp files to the project
5
Implementation of a Directed Graph ADT
Examine Digraph.h
Adjacency list representation.
The Digraph is a vector of Vertex objects
Node ID is the index.
Element 0 is not used.
Each Vertex object has a data member
Template class T
A list of integers (Node IDs)
Nodes adjacent to this node.
6
NetworkFile.txt
Example: Digraph with string as template
parameter.
Class Digraph method read() sets up the
digraph with contents of a file.
7
NetworkFile.txt
1
First number in each list is the
number of adjacencies.
2
The then IDs of adjacent cities.
3
4
5
Note that Denver has an
adjacency to itself.
(Sight-seeing flight? )
6
7
8
8
Adjacencies in NetworkFile.txt
Bos
5
Chi
LA
4
1
Den
3
NY
6
SF
2
NO
8
Miami
7
9
template <typename T>
void Digraph<T>::read(ifstream & inStream)
{
Vertex vi;
int n;
// number of adjacent vertices
int vertex_id;
// the number of a vertex
Digraph<T>::read()
// Create a garbage 0-th value so real indices start with 1
digraph.push_back(vi);
while (true)
{
inStream >> vi.data;
if (inStream.eof()) break;
vi.adjacencyList.clear();
inStream >> n; // Number of adjacent vertices
for (int i = 1; i <= n; i++)
{
inStream >> vertex_id;
assert(inStream.good());
vi.adjacencyList.push_back(vertex_id);
}
digraph.push_back(vi);
}
}
Digraph<T>::display( )
template <typename T>
void Digraph<T>::display(ostream & out)
{
out << "Adjacency-List Representation: \n";
for (size_t i = 1; i < digraph.size(); i++)
{
out << i << ": " << digraph[i].data << "--";
for (list<int>::iterator
it = digraph[i].adjacencyList.begin();
it != digraph[i].adjacencyList.end(); it++)
out << *it << " ";
out << endl;
}
}
11
Depth First Search
Public method:
void depthFirstSearch(int start = 1);
...
template <typename T>
inline void Digraph<T>::depthFirstSearch(int start)
{
vector<bool> unvisited(digraph.size(), true);
depthFirstSearch(start, unvisited);
}
12
Internal Depth First Search Method
// Internal (recursive) depth first search method
template <typename T>
void Digraph<T>::depthFirstSearch(int start, vector<bool> & unvisited)
{
visit(digraph[start].data);
unvisited[start] = false;
// Traverse the adjacency list, performing depth-first
// searches from each unvisited vertex in it.
list<int>::iterator it;
list<int>::iterator begin = digraph[start].adjacencyList.begin();
list<int>::iterator end = digraph[start].adjacencyList.end();
for (it = begin; it != end; it++)
{
// check if current vertex has been visited
if (unvisited[*it])
{
// Do a depth first search from this vertex
depthFirstSearch(*it, unvisited);
}
}
}
13
The visit() Method
template <typename T>
void Digraph<T>::visit(T& node_data)
{
cout << node_data << endl;
}
A Virtual Method
Intended to be overridden in a derived class in
order to do something useful at each node.
14
get_digraph()
void get_digraph()
{
ifstream network_file;
while (true)
{
cout << "Enter name of network file: ";
string filename;
cin >> filename;
network_file.open(filename.c_str());
if (network_file.is_open())
{
break;
}
cout << "Could not open " << filename << endl;
cout << "Please try again" << endl;
}
digraph.read(network_file);
network_file.close();
cout << "The Digraph's adjacency list representation:\n";
digraph.display(cout);
cout << endl;
}
15
Initial main()
int main()
{
get_digraph();
cout << endl << "Normal termination" << endl;
cin.get();
cin.get();
return 0;
}
16
The Adjacency Lists
17
Depth First Search
Let's do a Depth First Search.
int main()
{
get_digraph();
digraph.depthFirstSearch();
cout << endl << "Normal termination" << endl;
cin.get();
cin.get();
return 0;
}
18
Depth First Search from LA
19
Depth First Search from LA
Bos
5
Chi
LA
4
1
Den
3
NY
6
SF
2
NO
8
Miami
7
20
Depth First Search from Boston
Do a depth first search from Boston.
int main()
{
get_digraph();
digraph.depthFirstSearch(5);
21
Depth First Search from Boston
22
Depth First Search from Boston
Bos
5
Chi
LA
4
1
Den
3
NY
6
SF
2
NO
8
Miami
7
23
Providing Our Own Visit Method
Add derived class Digraph2.h
http://www.cse.usf.edu/~turnerr/Data_Structures/Downloads/
2011_04_25_Directed_Graphs/
Delete the .txt
24
Digraph2.h
#pragma once
#include "digraph.h"
template <typename T>
class Digraph2 : public Digraph<T>
{
public:
void visit(T& node_data);
};
Override visit()
method in base class
template <typename T>
void Digraph2<T>::visit(T& node_data)
{
show_length(node_data);
}
25
In shortest_path.cpp
#include "Digraph2.h"
Digraph2<string> digraph;
void show_length(string name)
{
cout << "Length of " << name << " is "
<< name.length() << endl;
}
26
Own Visit Method
End of Section
27
Paths
Routing problems – find an optimal path in a
network
Example – a directed graph that models an
airline network
A shortest path in a digraph.
A cheapest path in a weighted digraph.
Vertices represent cities.
Arcs represent flights connecting cities.
Task: Find most direct route between two cities.
(Fewest flights)
28
Paths in Directed Graph
Most direct route
Shortest path.
Path from start vertex to destination vertex
with minimum number of arcs.
Search algorithm for a shortest path:
A minor modification of the breadth-first
search algorithm.
Do a breadth first traversal, keeping track of
the predecessor of each node reached.
Stop upon reaching the destination node.
29
Shortest Path Algorithm
Given a directed graph with nodes 1 to n, a
starting node ID, start, and a destination
node ID, dest:
Let dist[] be an array of ints
Let pred[] be an array of node IDs.
dist[v] will hold the distance from start to
node v.
pred[v] will be the predecessor to node v on a
shortest path from start to dest.
Initialize dist[start] to 0 and dist[v] to
infinity for all other nodes.
30
Shortest Path Algorithm
Initialize vertex_queue as a queue of ints, initially
containing just the starting vertex ID.
While dest has not been visited and vertex queue
is not empty:
Remove the front item from the vertex queue as v.
For each node, w, adjacent to v:
If dist[w] is infinity
Set dist[w] to dist[v]+1
Set pred[w] to v.
Add w to the vertex queue.
31
Shortest Path Algorithm
At this point, either we have reached dest or we have
exhausted the possibilities.
If dist[dest] is infinity report failure.
Else
Initialize a stack with dest.
Initialize v as dest.
Do the following
Set v to pred[v]
Push v onto the stack
until v is start.
The stack now holds a shortest path from start to dest.
32
Implementation of Shortest_Path
In digraph.h
template<typename T>
vector<int> Digraph<T>::Shortest_Path(int start, int dest)
{
int n = digraph.size();
vector<int> dist(n, INT_MAX);
// Distance from start
vector<int> pred(n, 0);
// Predecessor on shortest path
int v; // The current vertex
queue<int> vertex_queue;
vertex_queue.push(start);
dist[start] = 0;
33
Implementation of Shortest_Path
while (dist[dest] == INT_MAX && !vertex_queue.empty())
{
v = vertex_queue.front();
vertex_queue.pop();
list<int>::iterator it;
list<int>::iterator begin = digraph[v].adjacencyList.begin();
list<int>::iterator end = digraph[v].adjacencyList.end();
for (it = begin; it != end; ++it)
{
int w = *it;
if (dist[w] == INT_MAX)
{
dist[w] = dist[v] + 1;
pred[w] = v;
vertex_queue.push(w);
}
}
}
34
Implementation of Shortest_Path
// Now reconstruct the shortest path if there is one
if (dist[dest] == INT_MAX)
{
cout << "Destination not reachable from start vertex\n";
return path;
}
stack<int> reverse_path;
reverse_path.push(dest);
v = dest;
do
{
v = pred[v];
reverse_path.push(v);
} while (v != start);
35
Implementation of Shortest_Path
vector<int> path;
while (!reverse_path.empty())
{
v = reverse_path.top();
path.push_back(v);
reverse_path.pop();
}
return path;
}
36
main()
int main()
{
get_digraph();
char response;
do
{
int start, destination;
cout << "Number of start city? ";
cin >> start;
cout << "Number of destination? ";
cin >> destination;
vector<int> path = digraph.Shortest_Path(start, destination);
if (path.size() > 0)
{
display_path(path);
}
else
{
cout << digraph.get_data(destination)
<< " is unreachable from "
<< digraph.get_data(start) << endl;
}
cout << endl << "More (Y or N)?";
cin >> response;
} while (response == 'y' || response == 'Y');
37
Try it!
38
Computing Shortest Paths
39
A Defect
What happens if we ask for the shortest
path from a city to itself?
40
A Defect
41
A Defect
What is the program doing?
What should it do?
End of Presentation
42