example: x y z t 5 vertices 6 edges s collection list set arraylist linkedlist sortedset hashset...
TRANSCRIPT
CHAPTER 14
GRAPHS
TREES
NETWORKS
AN UNDIRECTED GRAPH CONSISTS OFDISTINCT ITEMS CALLED VERTICESAND DISTINCT, UNORDEREDVERTEX-PAIRS CALLED EDGES.
EXAMPLE:
X
Y Z
T
5 VERTICES
6 EDGES S
Collection
List Set
ArrayList LinkedList SortedSet
HashSet TreeSet
TWO VERTICES ARE ADJACENT IF
THEY FORM AN EDGE. ADJACENT
VERTICES ARE CALLED NEIGHBORS.
List AND LinkedList ARE NEIGHBORS,
BUT NOT LinkedList AND ArrayList.
A PATH IN AN UNDIRECTED GRAPH
IS A SEQUENCE OF VERTICES IN
WHICH EACH SUCCESSIVE PAIR IS
AN EDGE. FOR EXAMPLE,
Collection, Set, SortedSet, TreeSet
THE LENGTH OF A PATH IS THE
NUMBER OF EDGES IN THE PATH.
FOR EXAMPLE, THE PATH
Collection, Set, SortedSet, TreeSet
HAS LENGTH 3.
X
Y Z
T
X, Y, T, Z, S HAS LENGTH 4.
SHORTEST PATH FROM
X to S = ? S
IN GENERAL, HOW CAN THE SMALLEST PATH
BETWEEN 2 VERTICES BE DETERMINED?
A CYCLE IS A PATH IN WHICH THE
FIRST AND LAST VERTICES ARE THE
SAME AND THERE ARE NO
REPEATED EDGES.
AN ACYCLIC GRAPH IS A GRAPH
WITH NO CYCLES.
X
Y Z
T
X, Y, T, Z, X IS A CYCLE.
Y, T, S, T, Y IS NOT A CYCLE.
S
IS Y, Z, T, S, Z, X, Y A CYCLE?
Collection
List Set
ArrayList LinkedList SortedSet
HashSet TreeSet
THIS UNDIRECTED GRAPH IS ACYCLIC.
AN UNDIRECTED GRAPH IS
CONNECTED IF THERE IS A PATH
BETWEEN ANY TWO DISTINCT
VERTICES IN THE GRAPH.
ALL OF THE ABOVE UNDIRECTED
GRAPHS ARE CONNECTED.
THE FOLLOWING GRAPH, WITH 6
VERTICES AND 6 EDGES, IS NOT
CONNECTED.
Minnesota Vikings
Chicago Bears Detroit Lions
Minnesota Twins
Chicago White Sox Detroit Tigers
A DIRECTED GRAPH – SOMETIMESCALLED A DIGRAPH – CONSISTS OFVERTICES AND EDGES; THE EDGESARE ORDERED PAIRS OF VERTICES.
AN ARROW IS DRAWN FROM THEFIRST VERTEX IN AN EDGE TO THESECOND VERTEX IN THAT EDGE.
Main Street
State Avenue Park Place
West Street East Street
South Kihei Road
A PATH IN A DIRECTED GRAPH IS A
SEQUENCE OF EDGES IN WHICH THE
SECOND VERTEX IN EACH EDGE
(EXCEPT THE LAST EDGE) IS THE
FIRST VERTEX IN THE NEXT EDGE.
THAT IS, A PATH MUST FOLLOW THE
DIRECTION OF THE ARROWS.
Main Street
State Avenue Park Place
West Street East Street
South Kihei Road
FIND A PATH FROM Park Place TO Main St.
A DIRECTED GRAPH IS CONNECTED
IF THERE IS A PATH BETWEEN ANY
PAIR OF VERTICES.
THE PATH MUST FOLLOW THE
DIRECTION OF THE ARROWS.
IS THE FOLLOWING GRAPH
CONNECTED?
Main Street
State Avenue Park Place
West Street East Street
South Kihei Road
A TREE, SOMETIMES CALLED A
DIRECTED TREE, IS A DIRECTED
GRAPH THAT EITHER IS EMPTY OR
HAS A VERTEX, CALLED THE ROOT,
SUCH THAT
1. THERE ARE NO EDGES COMINGINTO THE ROOT.
2. EVERY NON-ROOT VERTEX HASEXACTLY 1 EDGE COMING INTO IT.
3. THERE IS A PATH FROM THE ROOTTO EVERY OTHER ELEMENT.
Collection
List Set
ArrayList LinkedList SortedSet
HashSet TreeSet
SOMETIMES WE ASSOCIATE A NON-NEGATIVE NUMBER WITH EACHEDGE IN A GRAPH (DIRECTED ORUNDIRECTED). THE NON-NEGATIVENUMBERS ARE CALLED WEIGHTSAND THE RESULTING GRAPH ISCALLED A NETWORK OR WEIGHTEDGRAPH.
18 C F
3 15 4 10
12 5 19 A B D H
6 5 3 22 E G
GIVEN A PATH IN A NETWORK, THE
TOTAL WEIGHT OF THE PATH IS THE
SUM OF THE WEIGHTS OF THE
EDGES IN THE PATH.
18 C F
3 15 4 10
12 5 19 A B D H
6 5 3 22 E G
THE TOTAL WEIGHT OF THE PATH A,
C, F, H IS 31.
18 C F
3 15 4 10
12 5 19 A B D H
6 5 3 22 E G
THE TOTAL WEIGHT OF THE PATH A,B, D, H IS 36.
18 C F
3 15 4 10
12 5 19 A B D H
6 5 3 22 E G
EXERCISE: LIST ALL 8 PATHS FROM A TO H.
WHICH OF THOSE PATHS IS SHORTEST, THAT
IS, HAS THE LOWEST TOTAL WEIGHT?
GRAPH ALGORITHMS
ALL OF THE ALGORITHMS WE WILL
STUDY INVOLVE ITERATING, EITHER
THROUGH ALL VERTICES OR
THROUGH ALL VERTICES
REACHABLE FROM (THAT IS, ON
SOME PATH FROM) A GIVEN VERTEX.
BREADTH-FIRST ITERATION:
GIVEN A START VERTEX,
FIRST VISIT THE START VERTEX,
THEN VISIT ALL NOT-YET-REACHED NEIGHBORSOF THE START VERTEX,
THEN VISIT ALL NOT-YET-REACHED NEIGHBORSOF THOSE NEIGHBORS;
CONTINUE AS LONG AS THERE ARE ANYUNVISITED VERTICES TO WHICH THERE IS APATH FROM THE START VERTEX.
x v
Y Z
T
SASSUME THE VERTICES ARE ENTERED IN ALPHABETICAL ORDER.
PERFORM A BREADTH-FIRST ITERATION FROM S.
ANSWER: S, T, Z, Y, V, X
BASICALLY, FOR A BREADTH-FIRST ITERATION
FROM SOME VERTEX start, FIRST VISIT start,
THEN VISIT ALL THE UNVISITED VERTICES
THAT ARE ON A PATH OF LENGTH 1 FROM start,
THEN VISIT ALL THE UNVISITED VERTICES
THAT ARE ON A PATH OF LENGTH 2 FROM start,
AND SO ON.
breadth_first_iterator CLASS
METHODS?
breadth_first_iterator (const vertex* start), ++, !=, *
PRELIMINARY DESIGN:
WE NEED TO KEEP TRACK OF THECURRENT VERTEX, AND WHICHVERTICES HAVE BEEN REACHED. WEWILL RETRIEVE VERTICES IN THESAME ORDER THEY WERE SAVED.
DATA STRUCTURE?
A QUEUE!
breadth_first_iterator (vertex start){
for every vertex in the network:mark that vertex as not reached.
mark start as reached.vertex_queue.push (start);
} // algorithm for constructor
vertex operator*( ){
return vertex_queue.front( );
} // algorithm for operator*
breadth_first_iterator operator++ (int){
breadth_first_iterator temp = *this; current = vertex_queue.front( );
vertex_queue.pop( );
for each vertex that is a neighbor of current: if that vertex has not yet been reached
{mark that vertex as reached;
enqueue that vertex onto vertex_queue } // if
return temp;
} // algorithm for operator++ (int)
X V
Y Z
T
S
ASSUME THE EDGES ARE INSERTED INTO THE GRAPH AS FOLLOWS:
S, T (SAME AS T, S)S, ZT, YT, ZV, YV, ZX, YX, Z
PERFORM A BREADTH-FIRST ITERATION FROM S.
vertex_queue vertex where iterator returned by ++ is positioned S T, Z
S Z, Y
T Y, V, X
Z V, X
Y X
V X
NOTE: FOR A BREADTH-FIRST ITERATION OF A DIRECTED
GRAPH, THE ALGORITHM IS THE SAME, BUT “NEIGHBOR”
TAKES INTO ACCOUNT THE DIRECTION OF THE ARROW.
A
B C D
FOR A BREADTH-FIRST ITERATION STARTING AT A, THE
NEIGHBORS OF A ARE B AND C, BUT NOT D. D NEVER
GETS ENQUEUED, AND NEVER GETS RETURNED BY next( ).
DEPTH-FIRST ITERATOR RECALL THE PRE-ORDER
TRAVERSAL OF BINARY TREES:
preOrder (t) {
if (t is not empty) { access the root item of t; preOrder (leftTree (t)); preOrder (rightTree (t)); } // if } // preOrder traversal
Collection
List Set
ArrayList LinkedList SortedSet
HashSet TreeSet
DEPTH-FIRST ITERATION:
CollectionListArrayListLinkedListSetHashSetSortedSetTreeSet
SINCE A PRE-ORDER TRAVERSAL IS
RECURSIVE,WHAT DATA STRUCTURE SHOULD
WE USE TO HOLD THE VERTICES?
A STACK!
depth_first_iterator (vertex start) {
for every vertex in the network:mark that vertex as not reached.
mark start as reached.vertex_stack.push (start);
} // algorithm for constructor
depth_first_iterator operator++ (int){
depth_first_iterator temp = *this; current = vertex_stack.top( );
vertex_stack.pop( );
for each vertex that is a neighbor of current: if that vertex has not yet been reached
{mark that vertex as reached;
push that vertex onto vertex_stack } // if
return temp;
} // algorithm for operator++ (int) in a depth-first iteration
X V
Y Z
T
S
ASSUME THE EDGES ARE INSERTED INTO THE GRAPH AS
FOLLOWS:
S, T // SAME AS T, SS, ZT, YT, ZV, YV, ZX, YX, Z
PERFORM A DEPTH-FIRST ITERATION FROM S.
stack (top vertex is leftmost) vertex where iterator returned by ++ is positioned S Z, T S X, V, T Z Y, V, T X V, T Y T V
T
TOP OF STACK IS LEFTMOST.
IN A CONNECTED (DIRECTED OR
UNDIRECTED) NETWORK, A SPANNING
TREE IS A TREE THAT CONSISTS OF
ALL THE VERTICES AND SOME OF
THE EDGES – AND THEIR WEIGHTS.
A
5.0 7.0
B 10.0 C
8.0 6.0
D
HERE IS ONE SPANNING TREE:
A
5.0 7.0
B C
8.0
D
HERE IS ANOTHER SPANNING TREE: A
5.0 7.0
B 10.0 C
D
A MINIMUM SPANNING TREE HAS
LOWEST TOTAL WEIGHT AMONG
ALL SPANNING TREES.
IF THE WEIGHTS ARE DISTANCES
BETWEEN BUILDINGS, A MINIMUM
SPANNING TREE REPRESENTS THE
MINIMUM LENGTH OF CABLE
NEEDED TO CONNECT ALL THE
BUILDINGS.
FIND A MINIMUM SPANNING TREE:
A
5.0 7.0
B 10.0 C
8.0 6.0
D
A
5.0 7.0
B C
6.0
D
PRIM’S ALGORITHM FOR FINDING A MINIMUM
SPANNING TREE:
START WITH AN EMPTY TREE T AND PICK ANY
VERTEX v IN THE NETWORK. ADD v TO T.
FOR EACH VERTEX w SUCH THAT (v, w) IS AN
EDGE WITH WEIGHT wweight, SAVE THE
ORDERED TRIPLE <v, w, wweight> IN A
COLLECTION (SOON: WHAT KIND OF
COLLECTION).
THEN LOOP UNTIL T HAS AS MANY VERTICES
AS THE NETWORK. DURING EACH LOOP
ITERATION, REMOVE FROM THE COLLECTION
THE TRIPLE <x, y, yweight> FOR WHICH yweight IS
THE SMALLEST OF ALL TRIPLES IN THE
COLLECTION. IF y IS NOT ALREADY IN T, ADD y
AND THE EDGE (x, y) TO T, AND SAVE IN THE
COLLECTION EVERY TRIPLE <y, z, zweight> SUCH
THAT z IS NOT ALREADY IN T AND (y, z) IS AN
EDGE WITH WEIGHT zweight.
THE COLLECTION SHOULD BE ORDERED BY
WEIGHTS, AND DURING EACH LOOP ITERATION,
THE TRIPLE WITH LOWEST WEIGHT IS
REMOVED.
FOR THIS COLLECTION, SUPPOSE WE WANT, ON
AVERAGE, FOR INSERTIONS TO TAKE
CONSTANT TIME AND REMOVALS TO TAKE
LOGARITHMIC TIME. WHAT DATA STRUCTURE
DOES THIS SUGGEST FOR THE COLLECTION?
A PRIORITY QUEUE!
lowest weight = highest priority
A
5.0 7.0
B 10.0 C
8.0 6.0
D
SUPPOSE WE START WITH B.
T PRIORITY QUEUE B <B, A, 5>
<B, D, 8>
T PRIORITY QUEUE B <A, C, 7> 5 <B, D, 8>A <A, D, 10>
T PRIORITY QUEUE B <C, D, 6> 5 <B, D, 8>A C <A, D, 10> 7
T PRIORITY QUEUE B D <B, D, 8> 5 6 <A, D, 10>A C 7
WE ARE NOW DONE BECAUSE THE
TREE CONTAINS ALL OF THE
VERTICES.
EXERCISE:
FIND A MINIMUM SPANNING TREE
FOR THE FOLLOWING
UNDIRECTED NETWORK:
18 C F
3 15 4 10
12 5 19 A B D H
6 5 4 22 E G
FINDING THE SHORTEST
PATH THROUGH A NETWORK
GIVEN A NETWORK (DIRECTED ORUNDIRECTED) AND VERTICES v1 AND
v2, FIND A PATH FROM v1 TO v2
WHOSE TOTAL WEIGHT IS MINIMUM.
DIJKSTRA’S ALGORITHM:
LET pq BE A PRIORITY QUEUE OFVERTEX-WEIGHT PAIRS, <w, wweight>,WHERE wweight IS THE TOTAL WEIGHTOF ALL EDGES ON THE SHORTESTPATH SO FAR FROM v1 TO w.
LOWEST TOTAL WEIGHT= HIGHEST PRIORITY
ITERATE, BREADTH-FIRST, STARTINGAT v1 UNTIL A PAIR WITH v2 ISREMOVED FROM pq.
TO KEEP TRACK OF TOTAL PATH
WEIGHTS, WE HAVE A map OBJECT,weight_sum, THAT ASSOCIATES WITHEACH VERTEX x THE SUM OF THEWEIGHTS ON THE SHORTEST PATH SOFAR FROM v1 TO x.
FINALLY, predecessor, ANOTHER map
OBJECT, ASSOCIATES EACH VERTEX
x WITH ITS PREDECESSOR ON THESHORTEST PATH SO FAR FROM v1 TOx. THAT MAP ENABLES US TORETRIEVE THE SHORTEST PATH
WHEN WE ARE DONE.
B
10 18
A 2 D 25 7 5
C E 14
FIND THE SHORTEST PATH FROM A TO D.
INITIALIZE weight_sum AND predecessor,
AND FOR EACH NEIGHBOR w OF A,
ADD TO pq THE PAIR CONSISTING OF
THE NEIGHBOR AND THE WEIGHT OF
EDGE (A, w).
B weight_sum predecessor pq A, 0 A <C, 7> 10 18 B, 10 A <B, 10>
C, 7 AA 2 D D, 1000 25 E, 1000 7 5
C E 14
NOW LOOP UNTIL D IS REMOVED FROM pq. FOR
EACH PAIR <w, weight_sum> REMOVED FROM pq,
ITERATE OVER THE NEIGHBORS OF w. FOR
EACH NEIGHBOR x, IF w’S WEIGHT SUM +
WEIGHT OF (w, x) IS LESS THAN x’S WEIGHT SUM,
REPLACE x’S WEIGHT SUM WITH w’S WEIGHT
SUM + WEIGHT OF (w, x) AND INSERT x AND ITS
NEW WEIGHT SUM INTO pq. ALSO, MAKE w THE
PREDECESSOR OF x.
B weight_sum predecessor pq A, 0 A <B, 9> 10 18 B, 9 C <B, 10>
C, 7 A <E, 21>A 2 D D, 32 C <D, 32> 25 E, 21 C 7 5
C E 14
B weight_sum predecessor pq A, 0 A <B, 10> 10 18 B, 9 C <E, 21>
C, 7 A <D, 27>A 2 D D, 27 B <D, 32> 25 E, 21 C 7 5
C E 14
NOTHING HAPPENS WHEN <B, 10> IS REMOVED
FROM pq BECAUSE WE ALREADY HAVE A PATH
OF LENGTH 9 FROM A TO B.
B weight_sum predecessor pq A, 0 A <E, 21> 10 18 B, 9 C <D, 27>
C, 7 A <D, 32>A 2 D D, 27 B 25 E, 21 C 7 5
C E 14
B weight_sum predecessor pq A, 0 A <D, 26> 10 18 B, 9 C <D, 27>
C, 7 A <D, 32>A 2 D D, 26 E 25 E, 21 C 7 5
C E 14
DURING THE NEXT LOOP ITERATION, WHEN <D,
26> IS REMOVED FROM pq, WE STOP. THE
SHORTEST PATH FROM A TO D IS, ACCORDING
TO predecessor, A, C, E, D.
DEVELOPING A network CLASS
INSTEAD OF DEVELOPING SIX
CLASSES (DIRECTED OR UNDIRECTED
NETWORK, GRAPH AND TREE), WE
WILL DEVELOP A (DIRECTED)
network CLASS ONLY: THE OTHERS
CAN BE DEFINED BY INHERITANCE.
FOR EXAMPLES:
AN UNDIRECTED NETWORK IS A
(DIRECTED) NETWORK IN WHICH
EACH EDGE IS TWO-WAY.
A DIRECTED GRAPH IS A NETWORK
IN WHICH EACH EDGE HAS THE
SAME WEIGHT (FOR EXAMPLE, 1.0).
WHAT SHOULD WE START WITH?
FIELDS?
METHODS?
VERTEX-RELATED METHOD INTERFACES,
WITH TIME ESTIMATES GIVEN LATER:
// Postcondition: true has been returned if this network contains// v; otherwise, false has been returned.bool contains_vertex (const vertex& v);
// Postcondition: if v is already in this network, false has been// returned. Otherwise, the map with v and an// empty list has been added to this network and// true has been returned.bool insert_vertex (const vertex& v);
// Postcondition: if v is a vertex in this network, v and all of its// edges have been deleted from this network and// true has been returned. Otherwise, false has// been returned.bool erase_vertex (const vertex& v);
EDGE-RELATED METHOD INTERFACES:
// Postcondition: the number of edges in this network has been// returned.unsigned int get_edge_count();
// Postcondition: if <v1, v2> forms an edge in this network, the// weight of that edge has been returned.// Otherwise, -1.0 has been returned.double get_edge_weight (const vertex& v1, const vertex& v2);
// Postcondition: true has been returned if this network contains// the edge <v1, v2>. Otherwise, false has been// returned.bool contains_edge (const vertex& v1, const vertex& v2);
// Postcondition: if the edge <v1, v2> is already in this network// false has been returned. Otherwise, that edge// with the given weight has been inserted in this// network and true has been returned.bool insert_edge (const vertex& v1, const vertex& v2, const double& weight);
// Postcondition: if <v1, v2> is an edge in this network, that edge// has been removed and true has been returned.// Otherwise, false has been returned.bool erase_edge (const vertex& v1, const vertex& v2);
NETWORK-AS-A-WHOLE METHOD INTERFACES:
// Postcondition: this network is empty.network( );
// Postcondition: this network contains a copy of other.network (const network& other);
// Postcondition: the number of vertices in this network has been// returned.unsigned int size( );
// Postcondition: true has been returned if this network contains// no vertices. Otherwise, false has been returned.bool empty( );
// Precondition: v is in this network.// Postcondition: the list of neighbors of v has been returned.list< vertex > get_neighbor_list (const vertex& v);
// Postcondition: true has been returned if this network is// connected. Otherwise, false has been// returned.bool is_connected( );
// Precondition: this network is connected.// Postcondition: a minimum spanning tree for this network has// been returned.network<vertex> get_minimum_spanning_tree( );
// Postcondition: the shortest path from v1 to v2 and its total// weight have been returned.pair<list<vertex>, double> get_shortest_path (const vertex&v1, const vertex& v2);
// Postcondition: an iterator positioned at the beginning of this// network has been returned.iterator begin( );
// Postcondition: the iterator returned can be used in// comparisons to terminate an iteration of this// network.iterator end( );
// Precondition: vertex v is in this network.// Postcondition: a breadth_first_iterator over all vertices// reachable from v has been returned.breadth_first_iterator breadth_first_begin (const vertex& v);
// Postcondition: the breadth_first_iterator returned can be used// in comparisons to terminate this iteration of// this network.breadth_first_iterator breadth_first_end( );
// Precondition: vertex v is in this network.// Postcondition: a depth_first_iterator over all vertices// reachable from v has been returned.depth_first_iterator depth_first_begin (const vertex& v);
// Postcondition: the depth_first_iterator returned can be used// in comparisons to terminate this iteration of// this network.depth_first_iterator depth_first_end( );
FIELDS IN THE (DIRECTED) network
CLASS
GIVEN A VERTEX v, WHAT
INFORMATION ABOUT v ISRELEVANT?
ANSWER:
1. EACH VERTEX w SUCH THAT<v, w> FORMS AN EDGE;
2. THE WEIGHT OF THAT EDGE.
SO WITH EACH VERTEX v, WE WILL
ASSOCIATE ALL PAIRS <w, weight>
WHERE <v, w> FORMS AN EDGE
WHOSE WEIGHT IS weight.
HOW CAN WE SAVE “ALL PAIRS”?
A COLLECTION IN WHICH ORDER ISUNIMPORTANT:
A LINKED LIST
WHAT STRUCTURE SHOULD WE USE
TO “ASSOCIATE” v WITH ITS LINKED
LIST?
HINT: GIVEN A VERTEX, WE WANT
TO RETRIEVE ITS LINKED LIST VERY
QUICKLY.
BEST: A hash_map
BUT THE hash_map CLASS IS NOT
(YET) IN THE STANDARD TEMPLATELIBRARY. SO IN THE INTEREST OFCONFORMITY TO THE LIBRARY:
SECOND BEST: A map
EXERCISE:
USING weight_sum, predecessor, AND pq,
FIND THE SHORTEST PATH FROM A
TO H IN THE FOLLOWING NETWORK:
18 C F
3 15 4 10
12 5 19 A B D H
6 5 3 22 E G
THE network CLASS HAS ONLY ONEFIELD:
template<class vertex, class Compare = less<vertex> >class network{
protected:map<vertex, list< vertex_weight_pair >, Compare>
adjacency_map;
WHICH MAPS EACH VERTEX v TO
THE LinkedList OF NEIGHBORS OF v.
THIS DESIGN IS REFERRED TO AS THEADJACENCY LIST DESIGN OF THE
network CLASS.
WHAT IS vertex_weight_pair? ROUGHLY,A PAIR WITH A VERTEX AND AWEIGHT. TECHNICALLY:
struct vertex_weight_pair{ vertex to; // the end of the edge that starts // with the key vertex double weight;
// Postcondition: this vertex_weight_pair has been initialized// from x and y.
vertex_weight_pair (const vertex& x, const double& y) { to = x; weight = y; } // two-parameter constructor
// Postcondition: true has been returned if this// vertex_weight_pair is less than x.
// Otherwise, false has been returned. bool operator> (const vertex_weight_pair& p) const { return weight > p.weight; } // operator>}; // class vertex_weight_pair
THE REASON FOR OVERLOADINGoperator> IS THAT, IN THEget_shortest_path METHOD, THEPRIORITY QUEUE CONSISTS OFVERTEX-WEIGHT PAIRS, AND WEWANT THE LOWEST WEIGHT TOHAVE HIGHEST PRIORITY. SO THEFUNCTION CLASS FOR COMPARISONSMUST BE greater, NOT THE DEFAULT(less).
Mark
10.0 8.3
7.4 Karen Don Tara
14.2 20.0 15.0
Courtney
ASSUME THESE ARE ENTERED Karen, Mark,
Don, Courtney, Tara. HERE IS adjacency_map:
Karen [(Mark,10.0), (Don,7.4), (Courtney,14.2)]
Don [ ] Mark [(Tara,8.3)]
Courtney [(Don,20.0), (Tara,15.0)] Tara [ ]
METHOD DEFINITIONS IN THE
network CLASS
SEVERAL DEFINITIONS ARE ONE-
LINERS BECAUSE THE WORK IS
DONE IN THE map CLASS. FOR
EXAMPLE:
unsigned size( ) { return adjacency_map.size( ); } // method size bool contains_vertex (const vertex& v) { return adjacency_map.find (v) != adjacency_map.end( ); } // method contains_vertex
INSERTING A VERTEX CAN BE
ACCOMPLISHED WITH THE insert
METHOD IN THE map CLASS:
bool insert_vertex (const vertex& v){ return adjacency_map.insert (
pair<vertex, list<vertex_weight_pair> >(v, list<vertex_weight_pair>( ))).second ;
} // method insert_vertex
HERE IS ANOTHER DEFINITION OFinsert_vertex, ONE THAT IS LESSEFFICIENT BUT FAR EASIER TOUNDERSTAND:
bool insert_vertex (const vertex& v){ if (adjacency_map.find (v) != adjacency_map.end( )) return false; adjacency_map [v] = list< vertex_weight_pair >( ); return true;} // method insert_vertex
TO DELETE A VERTEX v, WE FIRST
UTILIZE THE find METHOD IN THE
map CLASS TO GET AN ITERATOR itr
POSITIONED AT v. WE THEN
DELETE THE VALUE (THAT IS,
VERTEX-LIST PAIR) THAT itr IS
POSITIONED AT:
bool erase_vertex (const vertex& v) { map_class::iterator itr = adjacency_map.find (v); if (itr == adjacency_map.end( )) return false; adjacency_map.erase (itr); WE MUST ALSO REMOVE ALL EDGES
GOING INTO v. SO WE ITERATE
THROUGH THE ADJACENCY MAP:
FOR EACH LIST, IF THERE IS A PAIR
WITH VERTEX v, THAT PAIR IS
DELETED FROM THE LIST:
bool erase_vertex (const vertex& v) { map_class::iterator itr = adjacency_map.find (v); if (itr == adjacency_map.end( )) return false; adjacency_map.erase (itr);
list<vertex_weight_pair>::iterator list_itr; for (itr = adjacency_map.begin( ); itr != adjacency_map.end( )); itr++)
// In the list in (*itr).second, delete any pair <v, ?> for (list_itr = (*itr).second.begin(); list_itr != (*itr).second.end(); list_itr++) if ((*list_itr).to == v) { (*itr).second.erase (list_itr); break; // to exit the inner for loop } // v found in the list (*itr).second return true; } // erase_vertex
TO DETERMINE IF THE NETWORK
CONTAINS AN EDGE <v1, v2>, WE
FIRST CHECK TO MAKE SURE BOTH
v1 AND v2 ARE IN THE ADJACENCY
MAP. IF SO, WE ITERATE THROUGH
v1’S ASSOCIATED LIST FOR A
VERTEX-WEIGHT PAIR WITH v2:
bool contains_edge (const vertex& v1, const vertex& v2) { map_class::iterator itr = adjacency_map.find (v1); if (itr == adjacency_map.end() || adjacency_map.find (v2) == adjacency_map.end()) return false; // See if v2 is in the list of vertices adjacent from v1: list<vertex_weight_pair >::iterator list_itr;
for (list_itr = ((*itr).second).begin(); list_itr != ((*itr).second).end(); list_itr++)
if ((*list_itr).to == v2) return true; return false; } // method contains_edge
map_class IS AN ABBREVIATION FOR map<vertex, list< vertex_weight_pair > , Compare>
TO INSERT AN EDGE <v1, v2> AND ITS
WEIGHT, WE (TRY TO) INSERT THE
VERTICES v1 AND v2, AND THEN
APPEND <v2, weight> TO THE LIST OF
VERTEX-WEIGHT PAIRS ASSOCIATED
WITH VERTEX v1:
bool insert_edge (const vertex& v1, const vertex& v2, double weight) { if (contains_edge (v1, v2)) return false; insert_vertex (v1); insert_vertex (v2); (*(adjacency_map.find(v1))).second.push_back (vertex_weight_pair (v2, weight)); return true; } // method insert_edge
TO DELETE EDGE <v1, v2>, ITERATE
OVER THE LIST ASSOCIATED WITH v1.
DELETE, FROM THE LIST, ANY PAIR
WHOSE FIRST COMPONENT IS v2:
bool erase_edge (const vertex& v1, const vertex& v2){ map_class::iterator itr = adjacency_map.find (v1);
if (itr == adjacency_map.end( )|| adjacency_map.find (v2) == adjacency_map.end())
return false;
// If <v1, v2> forms an edge, remove, from the list of edges// adjacent from v1, the edge <v1, v2> and its weight:
list<vertex_weight_pair >::iterator list_itr; for (list_itr = (*itr).second.begin( );
list_itr != (*itr).second.end(); list_itr++) if ((*list_itr).to == v2) { (*itr).second.erase (list_itr); return true; } // if return false;} // method erase_edge
FINALLY, WE’LL LOOK ATITERATING, SPECIFICALLY, DEPTH-FIRST ITERATING.
FOR A DEPTH-FIRST ITERATION, WENEED NOT ONLY A START VERTEX,BUT ALSO THE NETWORK WE AREITERATING OVER. A POINTER TO
adjacency_map IS SUFFICIENT: WE
DON’T NEED A COPY OF
adjacency_map.
// Precondition: vertex v is in this network.// Postcondition: a depth_first_iterator over all vertices// reachable from v has been returned.depth_first_iterator depth_first_begin (const vertex& v){ depth_first_iterator d_itr (v, &adjacency_map); return d_itr;} // method depth_first_begin
IN THE EMBEDDED depth_first_iterator
CLASS, WE’LL HAVE A STACK OFVERTICES. ALSO GIVEN A VERTEX,WE WANT A QUICK DETERMINATIONOF WHETHER THAT VERTEX IS
REACHABLE FROM THE STARTVERTEX, SO WE’LL MAP EACH
VERTEX TO true OR false. FINALLY,WE HAVE (A COPY OF) THEADJACENCY MAP:
class depth_first_iterator{ friend class network;
protected:
stack<vertex>* vertex_stack; map<vertex, bool, Compare>* reached; map_class* map_ptr;
BY USING POINTER FIELDS, WESIMPLIFY THE TEST FOR EQUALITYOF ITERATORS.
BEFORE WE GET TO THE DEFINITIONOF THE CONSTRUCTOR (CALLED BYdepth_first_begin), RECALL THEOUTLINE GIVEN EARLIER:
depth_first_iterator (vertex start) {
for every vertex in the network:mark that vertex as not reached.
mark start as reached.vertex_stack.push (start);
} // algorithm for constructor
depth_first_iterator (const vertex& start, map_class* ptr){
map_ptr = ptr; reached = new map<vertex, bool, Compare>(); vertex_stack = new stack<vertex>();
// Mark each vertex as not reached: map_class::iterator itr; for (itr = (*map_ptr).begin(); itr != (*map_ptr).end(); itr++) (*reached)[(*itr).first] = false;
(*reached)[start] = true; (*vertex_stack).push (start);} // two-parameter constructor
AS PROMISED, THE DEFINITION OF
operator== IS STRAIGHTFORWARD:
bool operator== (const depth_first_iterator& other){
return (vertex_stack == other.vertex_stack) && (reached == other.reached) && (map_ptr == other.map_ptr);} // operator==
BEFORE WE TACKLE operator++ (int),RECALL THE ALGORITHM GIVENEARLIER:
depth_first_iterator operator++ (int){
depth_first_iterator temp = *this; current = vertex_stack.top( );
vertex_stack.pop( );
for each vertex that is a neighbor of current: if that vertex has not yet been reached
{mark that vertex as reached;
push that vertex onto vertex_stack } // if
return temp;
} // algorithm for operator++ (int) in a depth-first iteration
depth_first_iterator operator++ (int){
depth_first_iterator temp = *this; vertex current = (*vertex_stack).top(); (*vertex_stack).pop(); map_class::iterator itr = (*map_ptr).find (current); list<vertex_weight_pair >::iterator list_itr; for (list_itr = (*itr).second.begin(); list_itr != (*itr).second.end(); list_itr++) { vertex to = (*list_itr).to; if ((*reached) [to] == false) { (*reached) [to] = true; (*vertex_stack).push (to); } // if } // for
if ((*vertex_stack).empty()) { vertex_stack = NULL; reached = NULL; map_ptr = NULL; } // if stack empty return temp;} // operator++
EXERCISE: FOR A DEPTH-FIRST ITERATOR,
operator* RETURNS A VERTEX, NAMELY,
(*vertex_stack).top( );
FOR A NETWORK ITERATOR, operator*
RETURNS A PAIR. WHAT ARE THE TYPES OF
THE COMPONENTS OF THE PAIR? THAT IS,
WHAT ARE THE TYPES OF (*itr).first AND
(*itr).second IF itr IS A NETWORK ITERATOR?