Graph Discrete Mathematics and Its Applications Baojian Hua
What ’ s a Graph? Graph: a group of vertices connected by edges
Why Study Graphs? Interesting & broadly used abstraction not only in computer science challenge branch in discrete math Ex: the 4-color problem hundreds of known algorithms with more to study numerous applications
Broad Applications GraphVerticesEdges communicationtelephonecables softwarefunctionscalls internetweb pagehyper-links social relationship peoplefriendship transportationcitiesroads ………
Graph Terminology vertex edge: directed vs undirected A sample graph taken from chapter 22 of Introduction to Algorithms.
Graph Terminology degree: in-degree vs out-degree
Graph ADT A graph is a tuple (V, E) V is a set of vertices v1, v2, … E is a set of vertex tuple Typical operations: graph creation search a vertex (or an edge) traverse all vertexes …
Example G = (V, E) V = {1, 2, 3, 4, 5, 6} E = {(1, 2), (2, 5), (3, 5), (3, 6), (4, 1), (4, 2), (5, 4), (6, 6)}
Representation Two popular strategies: array-based (adjacency matrix) Keep an extensible two-dimensional array M internally M[i][j] holds the edge info ’ of, if there exists one linear list-based (adjacency list) for every vertex vi, maintain a linear list list list stores vi ’ s out-going edges
Adjacency Matrix # # ## ## # # Note the hash function: hash (n) = n-1
Adjacency List >2 3->53->6 5 4->1 6 2->5 4->2 5->4 6->
Graph in C
“ graph ” ADT in C: Interface // We assume, in this slides, all graphs directed, // Undirected ones are similar and easier. // In file “graph.h” #ifndef GRAPH_H #define GRAPH_H typedef struct graphStruct *graph; graph newGraph (); void insertVertex (graph g, poly data); void insertEdge (graph g, poly from, poly to); // more to come later … #endif
Graph Implementation #1: Adjacency Matrix // adjacency matrix-based implementation #include “matrix.h” #include “hash.h” #include “graph.h” struct graphStruct { matrix m; // remember the index hash h; }; ###
Matrix Interface // file “matrix.h” #ifndef MATRIX_H #define MATRIX_H typedef struct matrixStruct *matrix; matrix newMatrix (); void matrixInsert (matrix m, int i, int j); int matrixExtend (matrix m); #endif // Implementation could make use of a two- // dimensional extensible array, leave to you.
Adjacency Matrix-based: Graph Creation graph newGraph () { graph g = malloc (sizeof (*g)); g->m = newMatrix (); // an empty matrix g->h = newHash (); return g; }
Adjacency Matrix-based: Inserting Vertices void insertVertex (graph g, poly data) { int i = matrixExtend (g->matrix); hashInsert (g->hash, data, i); return; } ### ### 4 4
Graph Implementation #1: Inserting Edges void insertEdge (graph g, poly from, poly to) { int f = hashLookup (g->hash, from); int t = hashLookup (g->hash, to); matrixInsert (g->matrix, f, t); return; } ### #### 4 4
Client Code graph g = newGraph (); insertVertex (g, 1); insertVertex (g, 2); … insertVertex (g, 6); insertEdge (g, 1, 2); insertEdge (g, 2, 5); … insertEdge (g, 6, 6);
Graph Representation #2: Adjacency List #include “linkedList.h” #include “graph.h” typedef struct graphStruct *graph; typedef struct vertexStruct *vertex; typedef struct edgeStruct *edge; struct graphStruct { linkedList vertices; }; struct vertexStruct { poly data; linkedList edges; }; struct edgeStruct { vertex from; vertex to; }
Graph Representation #2: Adjacency List #include “linkedList.h” #include “graph.h” typedef struct vertexStruct *vertex; typedef struct edgeStruct *edge; struct graphStruct { linkedList vertices; }; struct vertexStruct { poly data; linkedList edges; }; struct edgeStruct { vertex from; vertex to; } >10->20->3
Adjacency List-based: Graph Creation // I’ll make use of this convention for colors: // graph, linkedList, data, vertex, edge graph newGraph () { graph g = malloc (sizeof (*g)); g->vertices = newLinkedList (); return g; } vertices g /\
Adjacency List-based: Creating New Vertex // I’ll make use of this convention for colors: // graph, linkedList, data, vertex, edge vertex newVertex (poly data) { vertex v = malloc (sizeof (*v)); v->data = data; v->edges = newLinkedList (); return v; } data v /\ edges data
Adjacency List-based: Creating New Edge // I’ll make use of this convention for colors: // graph, linkedList, data, vertex, edge edge newEdge (vertex from, vertex to) { edge e = malloc (sizeof (*e)); e->from = from; e->to = to; return e; } from e to from to
Adjacency List-based: Inserting New Vertex void insertVertex (graph g, poly data) { vertex v = newVertex (data); linkedListInsertTail (g->vertices, v); return; } >10->20->3 4
Adjacency List-based: Inserting New Vertex void insertVertex (graph g, poly data) { vertex v = newVertex (data); linkedListInsertTail (g->vertices, v); return; } >10->20->3 4
Adjacency List-based: Inserting New Vertex void insertVertex (graph g, poly data) { vertex v = newVertex (data); linkedListInsertTail (g->vertices, v); return; } >10->20->3 4
Adjacency List-based: Inserting New Edge void insertEdge (graph g, poly from, poly to) { vertex vf = lookupVertex (g, from); vertex vt = lookupVertex (g, to); edge e = newEdge (vf, vt); linkedListInsertTail (vf->edges, e); return; } // insert 0-> >10->20->3 4
Adjacency List-based: Inserting New Edge void insertEdge (graph g, poly from, poly to) { vertex vf = lookupVertex (g, from); vertex vt = lookupVertex (g, to); edge e = newEdge (vf, vt); linkedListInsertTail (vf->edges, e); return; } >10->20->3 4
Adjacency List-based: Inserting New Edge void insertEdge (graph g, poly from, poly to) { vertex vf = lookupVertex (g, from); vertex vt = lookupVertex (g, to); edge e = newEdge (vf, vt); linkedListInsertTail (vf->edges, e); return; } >10->20->3 4
Adjacency List-based: Inserting New Edge void insertEdge (graph g, poly from, poly to) { vertex vf = lookupVertex (g, from); vertex vt = lookupVertex (g, to); edge e = newEdge (vf, vt); linkedListInsertTail (vf->edges, e); return; } >10->20->3 4 0->4
Adjacency List-based: Inserting New Edge void insertEdge (graph g, poly from, poly to) { vertex vf = lookupVertex (g, from); vertex vt = lookupVertex (g, to); edge e = newEdge (vf, vt); linkedListInsertTail (vf->edges, e); return; } >10->20->3 4 0->4
Example
Client Code for This Example: Step #1: Cook Data graph graph = newGraph (); nat n1 = newNat (1); nat n2 = newNat (2); nat n3 = newNat (3); nat n4 = newNat (4); nat n5 = newNat (5); nat n6 = newNat (6);
Client Code Continued: Step #2: Insert Vertices graphInsertVertex (graph, n1); graphInsertVertex (graph, n2); graphInsertVertex (graph, n3); graphInsertVertex (graph, n4); graphInsertVertex (graph, n5); graphInsertVertex (graph, n6);
Client Code Continued: Step #3: Insert Edges graphInsertEdge (graph, n1, n2); graphInsertEdge (graph, n2, n5); graphInsertEdge (graph, n3, n5); graphInsertEdge (graph, n3, n6); graphInsertEdge (graph, n4, n1); graphInsertEdge (graph, n4, n2); graphInsertEdge (graph, n5, n4); graphInsertEdge (graph, n6, n6); // Done! :-)
Example In Picture: An Empty Graph // I’ll make use of this convention for colors: // graph, linkedList, data, vertex, edge next data g
Example In Picture: After Inserting all Vertices // I’ll make use of this convention for colors: // graph, linkedList, data, vertex, edge next data g /\ data next/\
Example In Picture: After Inserting all Edges (Part) // I’ll make use of this convention for colors: // graph, linkedList, data, vertex, edge next data g /\ data next/\ from to from to
Graph Traversal
Searching The systematic way to traverse all vertex in a graph Two general methods: breath first searching (BFS) start from one vertex, first visit all the adjacency vertices depth first searching (DFS) eager method These slides assume the adjacency list representation
“ graph ” ADT in C: Interface // in file “graph.h” #ifndef GRAPH_H #define GRAPH_H typedef struct graphStruct *graph; typedef void (*tyVisit)(poly); graph newGraph (); void insertVertex (graph g, poly data); void insertEdge (graph g, poly from, poly to); void dfs (graph g, poly start, tyVisit visit); void bfs (graph g, poly start, tyVisit visit); // we’d see more later … #endif
Sample Graph
Sample Graph BFS bfs (g, 1, natOutput);
Sample Graph BFS bfs (g, 1, natOutput); print 1;
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2;
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; print 4;
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; print 4; print 5;
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; print 4; print 5; // a choice print 3;
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; print 4; print 5; // a choice print 3; print 6;
BFS Algorithm bfs (vertex start, tyVisit visit) { queue q = newQueue (); enQueue (q, start); while (q not empty) { vertex current = deQueue (q); visit (current); for (each adjacent vertex u of “current”){ if (not visited u) enQueue (q, u); }
BFS Algorithm void bfsMain (graph g, poly start, tyVisit visit) { vertex startV = searchVertex (g, start); bfs (startV, visit); for (each vertex u in graph g) if (not visited u) bfs (q, u); }
Sample Graph BFS bfs (g, 1, natOutput); Queue: 1
Sample Graph BFS bfs (g, 1, natOutput); print 1; Queue: 2, 4 Queue: 1
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; Queue: 2, 4 Queue: 1 Queue: 4, 5
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; print 4; Queue: 5 Queue: 2, 4 Queue: 1 Queue: 4, 5
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; print 4; print 5; Queue: Queue: 5 Queue: 2, 4 Queue: 1 Queue: 4, 5 Queue: 3
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; print 4; print 5; // a choice print 3; Queue: Queue: 5 Queue: 2, 4 Queue: 1 Queue: 4, 5 Queue: 3 Queue: 6
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; print 4; print 5; // a choice print 3; print 6; Queue: Queue: 5 Queue: 2, 4 Queue: 1 Queue: 4, 5 Queue: 3 Queue: 6 Queue:
Moral BFS is very much like the level-order traversal on trees Maintain internally a queue to control the visit order Obtain a BFS forest when finished
Sample Graph DFS dfs (g, 1, natOutput);
Sample Graph DFS dfs (g, 1, natOutput); print 1;
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2;
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5;
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4;
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; // a choice print 3;
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; // a choice print 3; print 6;
DFS Algorithm dfs (vertex start, tyVisit visit) { visit (start); for (each adjacent vertex u of “start”) if (not visited u) dfs (u, visit); }
DFS Algorithm void dfsMain (graph g, poly start, tyVisit visit) { vertex startV = searchVertex (g, start); dfs (startV, visit); for (each vertex u in graph g) if (not visited u) dfs (u, visit); }
Sample Graph DFS dfs (g, 1, natOutput); print 1; dfs(1)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; dfs(1) => dfs(2)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; dfs(1) => dfs(2) => dfs(5)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; dfs(1) => dfs(2) => dfs(5) => dfs(4)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; dfs(1) => dfs(2) => dfs(5) => dfs(4) => dfs(2)???
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; dfs(1) => dfs(2) => dfs(5)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; dfs(1) => dfs(2)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; dfs(1)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; dfs(1) =>dfs(4)???
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; dfs(1)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; empty!
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; // a choice print 3; dfs(3)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; // a choice print 3; print 6; dfs(3) =>dfs(6)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; // a choice print 3; print 6; dfs(3) =>dfs(6) =>dfs(6)???
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; // a choice print 3; print 6; dfs(3) =>dfs(6)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; // a choice print 3; print 6; dfs(3)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; // a choice print 3; print 6; dfs(3) =>dfs(5)???
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; // a choice print 3; print 6; dfs(3)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; print 5; print 4; // a choice print 3; print 6; empty!
Moral DFS is very much like the pre-order traversal on trees Maintain internally a stack to control the visit order for recursion function, machine maintain an implicit stack Obtain a DFS forest when finished
Edge Classification Once we obtain the DFS (or BFS) spanning trees (forests), the graph edges could be classified according to the trees: tree edges: edges in the trees forward edges: ancestors to descants back edges: descants to ancestors cross edges: others
Edge Classification Example tree edges: 1->2, 2->5, 5->4, 3->6 forward edges: 1->4 back edges: 4->2, 6->6 cross edges: 3->5