dijkstra's algorithm using a weighted graph 1. objective you will be able to: describe an adt...

36
Dijkstra's Algorithm Using a Weighted Graph 1

Upload: cyrus-sutherland

Post on 15-Dec-2015

222 views

Category:

Documents


1 download

TRANSCRIPT

Dijkstra's Algorithm

Using a Weighted Graph

1

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

Get_Node_ID

Also add to class definition.

private:

int Get_Node_ID(const T& Node) const;

15

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

Weighted_Graph.h

Add at top:

#include <iostream>

#include <iomanip>

17

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

Program Running

21

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

Program in Action

36