Discrete Mathematics and Graph Discrete Mathematics and Its Applications Baojian Hua bjhua@ustc.edu.cn
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 Graph Vertices Edges communication telephone cables software functions calls internet web page hyper-links social relationship people friendship transportation cities roads …
Graph Terminology 1 2 3 vertex edge: directed vs undirected 4 5 6 A sample graph taken from chapter 22 of Introduction to Algorithms.
Graph Terminology 1 4 2 6 5 3 degree: in-degree vs out-degree
Graph ADT A graph is a tuple (V, E) Typical operations: V is a set of vertices v1, v2, … E is a set of vertex tuple <vi, vj> 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), (4, 1), (3, 5), (3, 6), (4, 1), (4, 2), (5, 4), (6, 6)} 1 4 2 6 5 3
Representation Two popular strategies: array-based (adjacency matrix) Keep an extensible two-dimensional array M internally M[i][j] holds the edge info’ of <vi, vj>, if there exists one linear list-based (adjacency list) for every vertex vi, maintain a linear list list<vi> list<vi> stores vi’s outing edges
Adjacency Matrix # Note the hash function: hash (n) = n-1 1 4 2 6 5 3 1 2 3 4 5 # 1 2 Note the hash function: hash (n) = n-1 3 4 5
Adjacency List Notice the pointers! 1 1->2 2 2->5 3 3->5 3->6 4 4->1 4->2 5 5->4 Notice the pointers! 6 6->6
Graph in C
“graph” ADT in C: Interface // We assume, in this slides, all graphs directed, // and undirected ones are similar and easier. // in file “graph.h” #ifndef GRAPH_H #define GRAPH_H typedef struct graph *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 graph { matrix matrix; // remember the index hash hash; }; 1 2 3 # 1 2 3
Matrix Interface // file “matrix.h” #ifndef MATRIX_H #define MATRIX_H typedef struct matrix *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->matrix = newMatrix (); // an empty matrix g->hash = 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; } 1 2 3 4 # 1 2 3 # 1 1 2 2 3 3 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; } 1 2 3 4 # 1 2 3 # 1 1 2 2 3 3 4
Client Code graph g = newGraph (); insertVertex (g, 1); … insertVertex (g, 6); insertEdge (g, 1, 2); insertEdge (g, 2, 5); insertEdge (g, 6, 6); 1 4 2 6 5 3
Graph Representation #2: Adjacency List #include “linkedList.h” #include “graph.h” struct graph { linkedList vertices; }; typedef struct vertex *vertex; typedef struct edge *edge; struct vertex { poly data; linkedList edges; struct edge { vertex from; vertex to; }
Graph Representation #2: Adjacency List #include “linkedList.h” #include “graph.h” struct graph { linkedList vertices; }; typedef struct vertex *vertex; typedef struct edge *edge; struct vertex { poly data; linkedList edges; struct edge { vertex from; vertex to; } 1 2 3 0->1 0->2 0->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
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
Adjacency List-based: Inserting New Vertex void insertVertex (graph g, poly data) { vertex v = newVertex (data); linkedListInsertTail (g->vertices, v); return; } 1 2 3 0->1 0->2 0->3 4
Adjacency List-based: Inserting New Vertex void insertVertex (graph g, poly data) { vertex v = newVertex (data); linkedListInsertTail (g->vertices, v); return; } 1 2 3 0->1 0->2 0->3 4
Adjacency List-based: Inserting New Vertex void insertVertex (graph g, poly data) { vertex v = newVertex (data); linkedListInsertTail (g->vertices, v); return; } 1 2 3 0->1 0->2 0->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->4 1 2 3 0->1 0->2 0->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; } 1 2 3 0->1 0->2 0->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; } 1 2 3 0->1 0->2 0->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; } 0->1 0->2 0->3 0->4 1 2 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; } 0->1 0->2 0->3 0->4 1 2 3 4
Example 1 4 2 6 5 3
Client Code for This Example: Step #1: Cook Data str gname = newStr (“test”); graph graph = newGraph (gname); nat n1 = newNat (1); nat n2 = newNat (2); nat n3 = newNat (3); nat n4 = newNat (4); nat n5 = newNat (5); nat n6 = newNat (6); 1 2 3 4 5 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); 1 2 3 4 5 6
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! :-) 1 2 3 4 5 6
Example In Picture: An Empty Graph // I’ll make use of this convention for colors: // graph, linkedList, data, vertex, edge g next data
Example In Picture: After Inserting all Vertices // I’ll make use of this convention for colors: // graph, linkedList, data, vertex, edge g next /\ data 1 5 6 2 3 4 data next /\ /\ /\ /\ /\
Example In Picture: After Inserting all Edges (Part) // I’ll make use of this convention for colors: // graph, linkedList, data, vertex, edge g next /\ data 1 5 6 2 3 4 data next /\ /\ /\ /\ from from to 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 graph *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 1 2 3 4 5 6
Sample Graph BFS bfs (g, 1, natOutput); 1 2 3 4 5 6
Sample Graph BFS bfs (g, 1, natOutput); print 1; 1 2 3 4 5 6
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 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); 1 2 3 4 5 6 Queue: 1
Sample Graph BFS bfs (g, 1, natOutput); print 1; 1 2 3 4 5 6 Queue: 1
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 Queue: 1 Queue: 2, 4 Queue: 4, 5
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 Queue: 1 Queue: 2, 4 Queue: 4, 5 Queue: 5
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 Queue: 1 Queue: 3 Queue: 2, 4 Queue: 4, 5 Queue: 5 Queue:
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 Queue: 1 Queue: 3 Queue: 2, 4 Queue: 4, 5 Queue: 6 Queue: 5 Queue:
Sample Graph BFS bfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 Queue: 1 Queue: 3 Queue: 2, 4 Queue: 4, 5 Queue: 6 Queue: 5 Queue: 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); 1 2 3 4 5 6
Sample Graph DFS dfs (g, 1, natOutput); print 1; 1 2 3 4 5 6
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 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; 1 2 3 4 5 6 dfs(1)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(1) => dfs(2)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(1) => dfs(2) => dfs(5)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(1) => dfs(2) => dfs(5) => dfs(4)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(1) => dfs(2) => dfs(5) => dfs(4) => dfs(2)???
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(1) => dfs(2) => dfs(5)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(1) => dfs(2)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(1)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(1) =>dfs(4)???
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(1)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 empty!
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(3)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(3) =>dfs(5)???
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(3)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(3) =>dfs(6)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(3) =>dfs(6) =>dfs(6)???
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(3) =>dfs(6)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(3)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 6 dfs(3)
Sample Graph DFS dfs (g, 1, natOutput); print 1; // a choice print 2; 3 4 5 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 1 2 3 4 5 6