ppt

advertisement
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
Download