32
Graphs - according to the mathematicians An undirected graph is 2-tuple: G=(V,E) • a set of vertices • a set of edges Vertices = {A, B, C, D, E} Edges = { {A,B}, {A,C}, {A,D}, {B,D} } Vertices = Edges = Can a graph ...contain an edge from A to A? ...contain two edge from A to B?

Graphs - according to the mathematicians An undirected graph is 2-tuple: G=(V,E) a set of vertices a set of edges Vertices = {A, B, C, D, E} Edges = {

Embed Size (px)

Citation preview

Graphs - according to the mathematicians

An undirected graph is 2-tuple: G=(V,E) • a set of vertices • a set of edges

Vertices = {A, B, C, D, E}Edges = { {A,B}, {A,C}, {A,D}, {B,D} }

Vertices =Edges =

Can a graph ...contain an edge from A to A?

...contain two edge from A to B?

Graphs - more definitionsAn edge is a pair (v,w), where v, w V

Path: is a walk in which all vertices are unique

A walk is an alternating sequence of vertices and edges (starting and endingwith vertices) in which each edge is incident to the vertices that precede and follow it in the sequence.

e1

e2

e3

e4

Graphs - still more definitions

e1

e2

e3

e4

Directed Graph (digraphs)

Undirected Graph

An undirected graph is connected if there is a path from every vertex to every other vertex

Labeled Graphs

Designing GraphsAn undirected graph is 2-tuple: • a set of vertices • a set of edges

Graph<VertexKey>

constructor» + Graph()

«query» + boolean containsVertex( VertexKey v ) + boolean containsEdge(VertexKey v1, VertexKey v2 ) «update» + void insertVertex( VertexKey v ) + void insertEdge( VertexKey v1, VertexKey v2 ) + void removeVertex( VertexKey v ) + void removeEdge( VertexKey v1, VertexKey v2 )

Graph<VertexKey>

constructor» + Graph()

«query» + boolean containsVertex( VertexKey v ) + boolean containsEdge(VertexKey v1, VertexKey v2 ) «update» + void insertVertex( VertexKey v ) + void insertEdge( VertexKey v1, VertexKey v2 ) + void removeVertex( VertexKey v ) + void removeEdge( VertexKey v1, VertexKey v2 )

Graph ADTGraph<VertexKey> ADT Specifications

Domain A Graph consists of two parts

• VERTICES -- a set of VertexKey

• EDGES -- a set of <VertexKey, VertexKey>

Invariant (ForAll <v1, v2> EDGES : v1VERTICES and v2VERTICES and v1 ≠ v2 ) and (ForAll <v1,v2> EDGES and <v3,v4> EDGES and <v1,v2> ≠ <v3,v4> :

(v1 = v4) (v2 ≠ v3)

no loops

no reversed edges

Graph ADT Methods

Graph<VertexKey> ADT Specifications(continued)

Constructor Methods public Graph() post: VERTICES == {} and EDGES == {} Query Methods public boolean containsVertex(VertexKey v) post: result == (v VERTICES )

public boolean containsEdge(VertexKey v1, VertexKey v2) post: result == (ThereIs ed EDGES : ed == <v1,v2> or ed == <v2,v1>)

Graph ADT Methods

Graph<VertexKey> ADT Specifications(continued)

Update Methods public void insertVertex(VertexKey v) post: VERTICES == VERTICES@pre {v }

public void insertEdge(VertexKey v1, VertexKey v2) pre: v1 VERTICES and v2 VERTICES and not containsEdge(v1,v2) post: EDGES = EDGES@pre { <v1,v2> }

public void removeVertex(VertexKey v) post: VERTICES == VERTICES@pre {v }

and EDGES = EDGES@pre - { e | e EDGES@pre and ( e = <v, vs> or e = < vs,v > for some vertex vs

)

public void removeEdge(VertexKey v1, VertexKey v2) post: EDGES == EDGES@pre - { <v1,v2>, <v2,v1> }

What is different about a digraph ADT?

Digraph ADTDigraph<VertexKey> ADT Specifications

Domain A Digraph consists of two parts

• VERTICES -- a set of VertexKey

• ARCS -- a set of <VertexKey, VertexKey>

Invariant ( ForAll <fromV, toV> ARCS : fromV VERTICES and toV VERTICES )

Digraph ADT Methods

Digraph<VertexKey> ADT Specifications(continued)

Constructor Methods public Digraph() post: VERTICES == {} and ARCS == {} Query Methods public boolean containsVertex(VertexKey v) post: result == (v VERTICES )

public boolean containsArc(VertexKey fromV, VertexKey toV) post: result == (ThereIs arc ARCS : arc == <fromV,toV>)

Digraph ADT Methods

Digraph<VertexKey> ADT Specifications(continued)

Update Methods public void insertVertex(VertexKey v) post: VERTICES == VERTICES@pre {v }

public void insertArc(VertexKey fromV, VertexKey toV) pre: v1 VERTICES and v2 VERTICES post: ARCS = ARCS@pre { <fromV,toV> }

public void removeVertex(VertexKey v) pre: ForAll a == <fromV,toV> ARCS : (fromV v and toV v ) post: VERTICES == VERTICES@pre {v } public void removeArc(VertexKey fromV, VertexKey toV) post: ARCS == ARCS@pre - { <fromV,toV> }

Digraph ImplementationsDigraph<VertexKey> ADT Specifications

Domain A Digraph consists of two parts

• VERTICES -- a set of VertexKey

• ARCS -- a set of <VertexKey, VertexKey>Invariant ( ForAll <fromV, toV> ARCS : fromV VERTICES and toV VERTICES )

Implementation?

Using Integers as “Keys”Digraph<VertexKey>

constructor» + Digraph()

«query» + boolean containsVertex( VertexKey v ) + boolean containsArc(VertexKey fromV, VertexKey toV) «update» + void insertVertex( VertexKey v ) + void insertArc( VertexKey fromV, VertexKey toV ) + void removeVertex( VertexKey v ) + void removeArc( VertexKey fromV, VertexKey toV )

Digraph<VertexKey>

constructor» + Digraph()

«query» + boolean containsVertex( VertexKey v ) + boolean containsArc(VertexKey fromV, VertexKey toV) «update» + void insertVertex( VertexKey v ) + void insertArc( VertexKey fromV, VertexKey toV ) + void removeVertex( VertexKey v ) + void removeArc( VertexKey fromV, VertexKey toV )

Digraph

constructor» + Digraph()

«query» + boolean containsVertex( int v ) + boolean containsArc( int fromV, int toV ) «update» + void insertVertex( int v ) + void insertArc( int fromV, VertexKey toV ) + void removeVertex( int v ) + void removeArc( int fromV, int toV )

Digraph

constructor» + Digraph()

«query» + boolean containsVertex( int v ) + boolean containsArc( int fromV, int toV ) «update» + void insertVertex( int v ) + void insertArc( int fromV, VertexKey toV ) + void removeVertex( int v ) + void removeArc( int fromV, int toV )

Using Integers as “Keys”

Question: How would you implement such numbering?

Answer:

Why does this eliminate theneed to store vertices?

Graph • Breadth-first search

• Depth-first search

• Topological ordering: an ordering of vertices in a directed acyclic graph

A

DEB

C

Adjacency ListsConsider storing outgoing arcs “in” their vertices.

Performance?

[0]

[1]

[2]

[3]

[4]

[5]

[6]

...insertArc

...containsArc

...removeVertex

Path Finder MethodsDigraph

constructor» + Digraph()

«query» + boolean containsVertex( int v ) + boolean containsArc( int fromV, int toV ) + boolean pathExists( int fromV, int toV ) + int distance( int fromV, int toV ) «update» + void insertVertex( int v ) + void insertArc( int fromV, VertexKey toV ) + void removeVertex( int v ) + void removeArc( int fromV, int toV )

Digraph

constructor» + Digraph()

«query» + boolean containsVertex( int v ) + boolean containsArc( int fromV, int toV ) + boolean pathExists( int fromV, int toV ) + int distance( int fromV, int toV ) «update» + void insertVertex( int v ) + void insertArc( int fromV, VertexKey toV ) + void removeVertex( int v ) + void removeArc( int fromV, int toV )

pathExistspublic boolean pathExists(int fromV, int toV) { java.util.LinkedList<Integer> reachedQ, lastQ;

if (fromV == toV) // path of length zero return true; else { reachedQ = new java.util.LinkedList<Integer>(); reachedQ.addLast( fromV );

for (int step=1; step<=vertexCount-1; step++) { lastQ = reachedQ; reachedQ = new java.util.LinkedList<Integer>(); while (lastQ.size() != 0) { int reachedVertex = lastQ.removeFirst(); for (int v=0; v<=vertexCount; v++) if ( containsArc(reachedVertex, v) ) if (v == toV) return true; else reachedQ.addLast( v ); } } } return false;}

public boolean pathExists(int fromV, int toV) { java.util.LinkedList<Integer> reachedQ, lastQ;

if (fromV == toV) // path of length zero return true; else { reachedQ = new java.util.LinkedList<Integer>(); reachedQ.addLast( fromV );

for (int step=1; step<=vertexCount-1; step++) { lastQ = reachedQ; reachedQ = new java.util.LinkedList<Integer>(); while (lastQ.size() != 0) { int reachedVertex = lastQ.removeFirst(); for (int v=0; v<=vertexCount; v++) if ( containsArc(reachedVertex, v) ) if (v == toV) return true; else reachedQ.addLast( v ); } } } return false;}

How could performancebe improved for an adjacencylist representation?

This is an example of a Depth-first algorithm

pathExists (for adjacency lists)public boolean pathExists(int fromV, int toV) { java.util.LinkedList<Integer> reachedQ, lastQ;

if (fromV == toV) // path of length zero return true; else { reachedQ = new java.util.LinkedList<Integer>(); reachedQ.addLast( fromV );

for (int step=1; step<=vertexCount-1; step++) { lastQ = reachedQ; reachedQ = new java.util.LinkedList<Integer>(); while (lastQ.size() != 0) { int reachedVertex = lastQ.removeFirst(); for each (vertex, v, in the adjacency list of reachedVertex) if (v == toV) return true; else reachedQ.addLast( v ); } } return false;}

public boolean pathExists(int fromV, int toV) { java.util.LinkedList<Integer> reachedQ, lastQ;

if (fromV == toV) // path of length zero return true; else { reachedQ = new java.util.LinkedList<Integer>(); reachedQ.addLast( fromV );

for (int step=1; step<=vertexCount-1; step++) { lastQ = reachedQ; reachedQ = new java.util.LinkedList<Integer>(); while (lastQ.size() != 0) { int reachedVertex = lastQ.removeFirst(); for each (vertex, v, in the adjacency list of reachedVertex) if (v == toV) return true; else reachedQ.addLast( v ); } } return false;}

distance

public int distance(int fromV, int toV) { java.util.LinkedList<Integer> reachedQ, lastQ;

if (fromV == toV) // path of length zero return 0; else { reachedQ = new java.util.LinkedList<Integer>(); reachedQ.addLast( fromV );

for (int step=1; step<=vertexCount-1; step++) { lastQ = reachedQ; reachedQ = new java.util.LinkedList<Integer>(); while (lastQ.size() != 0) { int reachedVertex = lastQ.removeFirst(); for each (vertex, v, in the adjacency list of reachedVertex) if (v == toV) return step; else reachedQ.addLast( v ); } } } return -1;}

public int distance(int fromV, int toV) { java.util.LinkedList<Integer> reachedQ, lastQ;

if (fromV == toV) // path of length zero return 0; else { reachedQ = new java.util.LinkedList<Integer>(); reachedQ.addLast( fromV );

for (int step=1; step<=vertexCount-1; step++) { lastQ = reachedQ; reachedQ = new java.util.LinkedList<Integer>(); while (lastQ.size() != 0) { int reachedVertex = lastQ.removeFirst(); for each (vertex, v, in the adjacency list of reachedVertex) if (v == toV) return step; else reachedQ.addLast( v ); } } } return -1;}

How does the method change for distance( int fromV, int toV )

distance - for a weighted digraphA common variant of distance is called shortest path.

This algorithm begins with a labeled digraph in which arcs arelabeled with numeric weights.

Our first algorithm, known as Dijkstra’s Algorithm, assumes that all arc weights are positive.

Modifications to prior algorithm:

1) must check all possible paths.

2) must compare each total path weight to shortest thus far.

3) must store total path weight along with each queued vertex.

Shortest Pathpublic double shortestWeightedPath(int fromV, int toV) { java.util.LinkedList<Integer> reachedQ, lastQ; int shortestPathSoFar = maxPossiblePath+1;

if (fromV == toV) // path of length zero shortestPathSoFar = getArcWeight(fromV, toV); reachedQ = new java.util.LinkedList<Integer>(); reachedQ.addLast( fromV ); reachedQ.addLast(getArcWeight(fromV, toV)); // if there is no Arc, weight: 0

for (int step=1; step<=vertexCount-1; step++) { lastQ = reachedQ; reachedQ = new java.util.LinkedList<Integer>(); while (lastQ.size() != 0) { int reachedVertex = lastQ.removeFirst(); int pathLen = lastQ.removeFirst(); for each (vertex, v, in the adjacency list of reachedVertex) { lastQ.addLast( v ); lastQ.addLast( pathLen + getArcWeight(reachedVertex,v) ); if ( v == toV &&

&& pathLen+getArcWeight(reachedVertex,v) < shortestPathSoFar ) shortestPathSoFar = pathLen+getArcWeight(reachedVertex,v); } } } return shortestPathSoFar;}

public double shortestWeightedPath(int fromV, int toV) { java.util.LinkedList<Integer> reachedQ, lastQ; int shortestPathSoFar = maxPossiblePath+1;

if (fromV == toV) // path of length zero shortestPathSoFar = getArcWeight(fromV, toV); reachedQ = new java.util.LinkedList<Integer>(); reachedQ.addLast( fromV ); reachedQ.addLast(getArcWeight(fromV, toV)); // if there is no Arc, weight: 0

for (int step=1; step<=vertexCount-1; step++) { lastQ = reachedQ; reachedQ = new java.util.LinkedList<Integer>(); while (lastQ.size() != 0) { int reachedVertex = lastQ.removeFirst(); int pathLen = lastQ.removeFirst(); for each (vertex, v, in the adjacency list of reachedVertex) { lastQ.addLast( v ); lastQ.addLast( pathLen + getArcWeight(reachedVertex,v) ); if ( v == toV &&

&& pathLen+getArcWeight(reachedVertex,v) < shortestPathSoFar ) shortestPathSoFar = pathLen+getArcWeight(reachedVertex,v); } } } return shortestPathSoFar;}

...with Negative Weights

Question: What must change to allow for negative weights?

Answer: Dijkstra’s algorithm does not work

A B

C

2

3 -2

MultilistA multilist implementation:

(1) stores vertices in a list.

Example

(2) stores arcs in adjacency lists, but using pointers back to from vertices.

Adjacency MatricesYet another representation - one bit per potential arc.

Performance?

boolean[][] digraph = boolean[maxV][maxV];

[0]

[1]

[2]

[3]

[4]

[5]

[6]

[0] [1] [2] [3] [4] [5] [6]

Trees & Forests

How would you define a tree (from an undirected graph)?

A forest is an undirected graph consisting of zero or moreunconnected components such that each component is a tree.

Spanning Tree

A spanning tree for a particular graph is a tree that

(1)includes all of the graph’s vertices and(2) includes a subset of the graph’s edges.

Suggest example spanning trees.

Minimum Weight Spanning Tree

A minimum weight spanning tree for a particular weighted graph is a spanning tree with total of all edge weights less than or equal to that of all other spanning trees for the graph.

Applications?

Kruskal’s Algorithm

Construct a sequence of forests (F0, F1, ... Fn) using only vertices and edges from an original digraph D, such that(a) F0 is the empty forest.(b) Fj+1 is formed by adding an edge and incident vertices to Fj. This edge must have minimum weight among D’s edges that are not in Fj.

Kruskal’s Algorithm Example F0 : the empty forest

F1 ?

Prim’s AlgorithmConstruct a sequence of trees (T1, T2, ... Tn) using

only vertices and edges from an original digraph D, such that(a) T1 consists of any single vertex of D.(b) Tj+1 is formed by adding an edge and vertex to Tj.

This edge must be have minimum weight among D ’s edges that are not in Tj and are incident to one

of Tj’s vertices.

Prim’s Algorithm Example

T1 ?