dijkstra's algorithm using a weighted graph 1. objective you will be able to: describe an adt...
TRANSCRIPT
Objective
You will be able to: Describe an ADT for a weighted graph. Implement an ADT for a weighted graph. Implement Dijkstra's algorithm for finding the
minimum cost path between two nodes in a weighted graph.
2
Edsger Dijkstra
1959 Shortest Path Algorithm (Graph Theory) 1968 The "THE" Operating System 1968 "Go To Consider Harmful" (Niklaus Wirth,
Editor) 1972 ACM Turing Award 1984 - 2002 University of Texas http://en.wikipedia.org/wiki/Edsger_W._Dijkstra
1930 - 2002
3
A Weighted Graph ADT
A Set of Nodes (Vertices) Numbered 1 .. N
A Set of bidirectional Edges (pairs of Nodes) A nonnegative weight for each edge. "Cost" or "Distance"
4
Problem: Find Best Path
Find a Path from a specified starting node to a specified destination node such that the sum of the weights of the edges is minimized.
5
A Weighted Graph ADT
Create a new project. Weighted_Graph_Demo
Add main.cpp Start with "Hello, World!"
6
main.cpp
#include <iostream>
using namespace std;
int main (void)
{
cout << "This is the Weighted Graph Demo\n";
cin.get();
return 0;
}
7
Weighted_Graph.h
Add new item: Weighted_Graph.h
This will be our weighted graph ADT template.
Will represent the graph with an adjacency matrix. distance[i][j] is distance from node i to node j
weight of the edge between node i and node j 0 if no edge between i and j
8
The Weighted Graph ADT
Nodes will be an arbitrary type. Template parameter T Must define operators =, ==, and <<
Externally nodes are identified by objects of class T. Example: Strings
Internally nodes are identified by integer Node IDs, 1 ... N
9
Weighted_Graph.h#pragma once
#ifndef MAX_NODES
#define MAX_NODES 100
#endif
using namespace std;
template <typename T>
class Weighted_Graph
{
private:
int number_of_nodes;
// The Node ID 0 is not used. The first real node has ID 1
T nodes[MAX_NODES+1];
int distance[MAX_NODES+1][MAX_NODES+1];
public:
Weighted_Graph();
void Add_Node(const T& node);
void Add_Edge(const T& Node_1, const T& Node_2, int dist);
void Display() const;
};10
Implementation
Constructor
template <typename T>
Weighted_Graph<T>::Weighted_Graph() : number_of_nodes(0)
{};
11
Add_Node
template <typename T>
void Weighted_Graph<T>::Add_Node (const T& node)
{
assert(number_of_nodes < MAX_NODES);
int n = ++number_of_nodes;
nodes[n] = node;
for (int i = 1; i < n; ++i)
{
distance[i][n] = 0;
distance[n][i] = 0;
}
}
12
Add_Edge
template <typename T>
void Weighted_Graph<T>::Add_Edge(const T& Node_1,
const T& Node_2,
int dist)
{
int Node_ID_1 = Get_Node_ID(Node_1);
int Node_ID_2 = Get_Node_ID(Node_2);
assert ((Node_ID_1 > 0) && (Node_ID_2 > 0));
distance[Node_ID_1][Node_ID_2] = dist;
distance[Node_ID_2][Node_ID_1] = dist;
}
Add at top:#include <cassert>
13
Get_Node_ID
template <typename T>
int Weighted_Graph<T>::Get_Node_ID(const T& node) const
{
for (int i = 1; i <= number_of_nodes; ++i)
{
if (nodes[i] == node)
{
return i;
}
}
cout << "Node " << node << " not found\n";
return -1;
}
14
Display
template <typename T>
void Weighted_Graph<T>::Display() const
{
cout << endl;
cout << setw(10) << " ";
for (int i = 1; i <= number_of_nodes; ++i)
{
cout << setw(10) << nodes[i] << " ";
}
cout << endl;
for (int i = 1; i <= number_of_nodes; ++i)
{
cout << setw(10) << nodes[i];
for (int j = 1; j <= number_of_nodes; ++j)
{
cout << setw(10) << distance[i][j] << " ";
}
cout << endl;
}
cout << endl;
} 16
Example: Airline connections
Dallas
Austin
Washington
Denver
Chicago
Houston
Atlanta
1000900
1400
780
200
1300
160
800
600
18
main.cpp
#include <iostream>
#include <string>
#include "Weighted_Graph.h"
using namespace std;
Weighted_Graph<string> connections;
19
Add to main()
connections.Add_Node(string("Atlanta"));
connections.Add_Node(string("Austin"));
connections.Add_Node(string("Chicago"));
connections.Add_Node(string("Dallas"));
connections.Add_Node(string("Denver"));
connections.Add_Node(string("Houston"));
connections.Add_Node(string("Washington"));
connections.Add_Edge(string("Atlanta"), string("Denver"), 1400);
connections.Add_Edge(string("Atlanta"), string("Houston"), 800);
connections.Add_Edge(string("Atlanta"), string("Washington"), 600);
connections.Add_Edge(string("Austin"), string("Dallas"), 200);
connections.Add_Edge(string("Austin"), string("Houston"), 160);
connections.Add_Edge(string("Chicago"), string("Dallas"), 900);
connections.Add_Edge(string("Chicago"), string("Denver"), 1000);
connections.Add_Edge(string("Dallas"), string("Denver"), 780);
connections.Add_Edge(string("Dallas"), string("Washington"), 1300);
connections.Display();
20
Dijkstra's Algorithm Given a starting node and a destination node
Push outward from the starting node Keeping track of the shortest total distance seen
so far to each node and the predecessor to that node on the shortest path seen so far.
Initially if the node is adjacent to the start Shortest total distance seen so far is the weight of the
link Predecessor on best path is the start
If node is not adjacent Shortest distance seen so far is infinity (INT_MAX)
22
Dijkstra's Algorithm
On each step of the iteration, the shortest total distance to one more node will be determined And its predecessor on the best path to it
from the starting node.
Keep track of which nodes we know the shortest distance to. Boolean array indexed by Node ID
23
Dijkstra's Algorithm
At each step of the iteration:
Determine a node with smallest "Best total distance seen so far" among the nodes for which the best total distance has not yet been determined.
Call it node N.
The best distance so far for node N is the actual best distance.
The predecessor for which that distance was determined is is predecessor on the best path.
The best path to that node is now known.
24
Dijkstra's Algorithm
Update best distances
For each node, i, for which the best path has not yet been determined -- Check if the node N provides a better path
than the best seen so far. Is Total Distance[N] + Distance(N,i) less than
Best Total Distance Seen So for for Node i?
If so, make that the new best total distance so far and make node N the predecessor.
25
Dijkstra's Algorithm
Continue the iteration until the actual shortest total distance for the destination has been determined.
We then know the shortest path length from Start to Destination and the best path. Follow predecessors from Destination back to
Start.
26
Best_Path
Add to Weighted_Graph class defintion:#include <deque>
public:
...
deque<T> Best_Path(const T& Start, const T& Dest) const;
Will return the best path from Start to Dest to the caller in the form of an STL deque. doubly ended queue
27
Best_Path// Dijkstra's Algorithm
template <typename T>
deque<T> Weighted_Graph<T>::Best_Path(const T& Start, const T& Dest) const
{
deque<T> best_path;
int best_total_distance_so_far[MAX_NODES+1];
int predecessor[MAX_NODES+1];
bool best_total_distance_is_known[MAX_NODES+1];
if (Dest == Start)
{
cout << "Dest = Start in call to Best_Path\n";
return best_path; // Return empty deque.
}
int Start_ID = Get_Node_ID(Start);
int Dest_ID = Get_Node_ID(Dest);
if ((Start_ID <= 0) || (Dest_ID <= 0))
{
cout << "Invalid start or destination\n";
return best_path; // empty deque
}28
Best_Path
for (int i = 1; i <= MAX_NODES; ++i)
{
if (distance[Start_ID][i] > 0)
{
best_total_distance_so_far[i] = distance[Start_ID][i];
predecessor[i] = Start_ID;
}
else
{
best_total_distance_so_far[i] = INT_MAX;
predecessor[i] = -1;
}
best_total_distance_is_known[i] = false;
}
best_total_distance_so_far[Start_ID] = 0;
best_total_distance_is_known[Start_ID] = true;
29
Best_Path (continued)
while (!best_total_distance_is_known[Dest_ID])
{
// Determine the node with least distance among
// all nodes whose best distance is not yet known.
int min_best_dist = INT_MAX;
int best_node_id = -1;
for (int i = 1; i <= number_of_nodes; ++i)
{
if (best_total_distance_is_known[i])
{
continue;
}
if (best_total_distance_so_far[i] < min_best_dist)
{
min_best_dist = best_total_distance_so_far[i];
best_node_id = i;
}
}
30
Best_Path (continued)
if (best_node_id == -1)
{
// Destination is unreachable.
cout << Dest << " is unreachable from " << Start << endl;
return best_path; // empty deque
}
// Best total distance so far for this node is the actual
// best total distance .
int n = best_node_id;
best_total_distance_is_known[n] = true;
31
Best_Path (continued) // Check if this node provdes a better route to the destination
// for other nodes whose best distance is not yet known.
for (int i = 1; i <= number_of_nodes; ++i)
{
if (best_total_distance_is_known[i])
{
continue;
}
if (distance[n][i] <= 0)
{
continue; // No connection from node n to node i
}
if ((best_total_distance_so_far[n] + distance[n][i]) <
best_total_distance_so_far[i])
{
// It does.
best_total_distance_so_far[i] =
best_total_distance_so_far[n] + distance[n][i];
predecessor[i] = n;
}
}
}32
Best_Path (continued)
// At this point we know predecessor of each node on the
// best path from Start to Dest
best_path.push_front(Dest);
int next_node_id = Dest_ID;
while (next_node_id != Start_ID)
{
next_node_id = predecessor[next_node_id];
best_path.push_front(nodes[next_node_id]);
}
return best_path;
}
33
main.cpp
void Show_Best_Path(string Start, string Dest)
{
deque<string> best_path = connections.Best_Path(Start, Dest);
if (best_path.size() == 0)
{
cout << "No path found\n";
}
else
{
cout << "Best path:\n";
while (best_path.size() > 0)
{
string next = best_path.front();
best_path.pop_front();
cout << next << endl;
}
}
cout << endl;
}
34
main.cpp
connections.Display();
cout << endl;
while (true)
{
string start;
string dest;
cout << "Start: ";
getline(cin, start);
cout << "Destination: ";
getline(cin, dest);
Show_Best_Path(start, dest);
}
cin.get();
return 0;
}
35