Lecture #13 Topics 1. The Graph Abstract Data Type. 2. Graph Representations. 3. Elementary Graph Operations. The Graph ADT • Definitions – A graph G consists of two sets • a finite, nonempty set of nodes V(G) • a finite, possible empty set of edges E(G) – G(V,E) represents a graph – An undirected graph is one in which the pair of nodes in an edge is unordered, (v0, v1) = (v1,v0) – A directed graph is one in which each edge is a directed pair of nodes, <v0, v1> != <v1, v0> tail head The Graph ADT • Examples for Graph – complete undirected graph: n(n-1)/2 edges – complete directed graph: n(n-1) edges 1 0 0 0 2 1 3 G1 complete graph V(G1)={0,1,2,3} V(G2)={0,1,2,3,4,5,6} V(G3)={0,1,2} 1 2 3 0 3 1 2 5 4 G2 6 2 G3 incomplete graph E(G1)={(0,1),(0,2),(0,3),(1,2),(1,3),(2,3)} E(G2)={(0,1),(0,2),(1,3),(1,4),(2,5),(2,6)} E(G3)={<0,1>,<1,0>,<1,2>} The Graph ADT • Restrictions on graphs – A graph may not have an edge from a node, i, back to itself. Such edges are known as self loops – A graph may not have multiple occurrences of the same edge. If we remove this restriction, we obtain a data referred to as a multigraph feedback loops multigraph The Graph ADT • Adjacent and Incident • If (v0, v1) is an edge in an undirected graph, – v0 and v1 are adjacent – The edge (v0, v1) is incident on nodes v0 and v1 V0 V1 • If <v0, v1> is an edge in a directed graph – v0 is adjacent to v1, and v1 is adjacent from v0 – The edge <v0, v1> is incident on v0 and v1 V0 V1 The Graph ADT • A subgraph of G is a graph G’ such that V(G’) V(G) and E(G’) E(G). 0 1 2 3 G1 0 1 2 G3 The Graph ADT • Path – A path from node vp to node vq in a graph G, is a sequence of nodes, vp, vi , vi , ..., vi , vq, such that (vp, vi ), (vi , vi ), ..., (vi , vq) are edges in an undirected graph. 1 1 2 2 n 1 n • A path such as (0, 2), (2, 1), (1, 3) is also written as 0, 2, 1, 3 – The length of a path is the number of edges on it 0 1 0 2 3 1 0 2 3 1 2 3 The Graph ADT • Simple path and cycle – simple path (simple directed path): a path in which all nodes, except possibly the first and the last, are distinct. – A cycle is a simple path in which the first and the last nodes are the same. 0 1 2 3 The Graph ADT • Connected graph – In an undirected graph G, two nodes, v and v , are connected if there is a path in G from v to v – An undirected graph is connected if, for every pair of distinct nodes v , v , there is a path from v to v 0 1 0 i j 1 i j • Connected component – A connected component of an undirected graph is a maximal connected subgraph. – A tree is a graph that is connected and acyclic (i.e, has no cycle). The Graph ADT • Strongly Connected Component – A directed graph is strongly connected if there is a directed path from vi to vj and also from vj to vi – A strongly connected component is a maximal subgraph that is strongly connected 0 1 2 G3 not strongly connected strongly connected component (maximal strongly connected subgraph) 0 1 2 The Graph ADT • Degree – The degree of a node is the number of edges incident to that node. • For directed graph – in-degree (v) : the number of edges that have v as the head – out-degree (v) : the number of edges that have v as the tail • If di is the degree of a node i in a graph G with n nodes and e edges, the number of edges is e( n 1 d ) / 2 i 0 The Graph ADT • Degree (cont’d) • We shall refer to a directed graph as a digraph. When we us the term graph, we assume that it is an undirected graph directed graph undirected graph degree 2 3 0 3 1 2 3 1 3 3 3 G1 in-degree & out-degree 0 in:1, out: 1 1 in: 1, out: 2 2 in: 1, out: 0 0 3 3 1 2 1 1 5 4 G2 1 6 G3 The Graph ADT • Abstract Data Type Graph struct Graph is object: a nonempty set of nodes and a set of undirected edges, where each edge is a pair of nodes. functions: for all graph Graph, v, v1 and v2 Nodes Graph Create( ) ::= return an empty graph. Graph InsertNode( Graph, v) ::= return a graph with v inserted v has no incident edges. Graph InsertEdge(Graph, v1 , v2 ) ::= return a graph with a new edges between v1 and v2 . Graph DeleteNode(Graph, v) ::= return a graph in which v and all edges incident to it are removed. Graph DeleteEdge(Graph, v1 , v2 ) ::= return a graph in which the edge (v1 , v2) is removed. Leave the incident nodes in the graph. bool IsEmpty(graph) ::= if(graph==empty graph) return True else return False. List Adjacent(graph) ::= return a list of all nodes that are adjacent to v. 2 Graph Representations • Adjacency Matrix • Adjacency Lists • Adjacency Multilists Graph Representations 4 5 • Adjacency Matrix 6 – Let G = (V,E) be a graph with n nodes. – The adjacency matrix of G is a two-dimensional 7 n x n array, say adj_mat 0 – If the edge (vi, vj) is(not) in E(G), adj_mat[i][j]=1(0) 1 2 – The adjacency matrix for an undirected graph is symmetric; 3 G4 the adjacency matrix for a digraph need not be symmetric 0 1 1 0 0 0 0 0 0 0 1 2 3 G1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 G3 2 0 1 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 Graph Representations • Meritx of Adjacency Matrix – For an undirected graph, the degree of any node, i, is its row sum: n 1 adj _ mat[i][ j] j 0 – For a directed graph, the row sum is the out-degree, while the column sum is the in-degree. n 1 n 1 j 0 j 0 ind (vi ) A[ j , i ] outd (vi ) A[i , j ] – The complexity of checking edge number or examining if G is connect • G is undirected: O(n2/2) • G is directed: O(n2) Graph Representations • Adjacency lists – There is one list for each node in G. The nodes in list i represent the nodes that are adjacent from node i – For an undirected graph with n nodes and e edges, this representation requires n head nodes and 2e list nodes – C declarations for adjacency lists #define MAX_NODES 50; /* maximum number of nodes*/ struct node { int node; node * link; } node graph(MAX_NODES); int n=0; /* nodes currently in use */ 0 • Example 4 0 1 2 1 2 6 3 3 0 1 2 3 1 0 0 0 7 2 2 1 1 G1 0 1 2 1 0 2 G3 5 3 3 3 2 0 1 2 0 1 2 3 4 5 6 7 1 0 0 1 5 4 5 6 G4 2 3 3 2 6 7 An undirected graph with n vertices and e edges ==> n head nodes and 2e list nodes Graph Representations • Adjacency Multilists Marked node1 node2 path1 – Lists in which nodes may be shared among several lists. (an edge is shared by two different paths) – There is exactly one node for each edge. – This node is on the adjacency list for each of the two nodes it is incident to struct edge { short int market; int node1; int node2 edge * path1; edge * path2; } edge graph(MAX_NODES); path2 Graph Representations • Example for Adjacency Multlists 0 1 2 3 The lists are: node 0: N1 N2 N3 node 1: N1 N4 N5 node 2: N2 N4 N6 node 3: N3 N5 N6 Graph Representations • Weighted edges – The edges of a graph have weights assigned to them. – These weights may represent as • the distance from one node to another • cost of going from one node to an adjacent node. – adjacency matrix: adj_mat[i][j] would keep the weights. – adjacency lists: add a weight field to the node structure. – A graph with weighted edges is called a network 3 Graph Operations • Traversal Given G=(V,E) and node v, find all wV, such that w connects v – Depth First Search (DFS): preorder traversal – Breadth First Search (BFS): level order traversal • Spanning Trees • Biconnected Components Graph Traversal • Problem: Search for a certain node or traverse all nodes in the graph • Depth First Search – Once a possible path is found, continue the search until the end of the path • Breadth First Search – Start several paths at a time, and advance in each one step at a time Graph Traversal • Example for traversal (using Adjacency List representation of Graph) depth first search (DFS): v0, v1, v3, v7, v4, v5, v2, v6 breadth first search (BFS): v0, v1, v2, v3, v4, v5, v6, v7 Depth-First Search A B C D E F G H I J K L M N O P • Depth First Search void dfe(int v) { /* depth first search of a graph begin*/ node w; visited[v]= TRUE; cout<<v; for (w=graph(v); w; w= w->link) if (!visited[w->node]) dfs(w->node); } w Data structure adjacency list: O(e) adjacency matrix: O(n2) short int visited[MAX_NODES]; [0] [1] [2] [3] [4] [5] [6] [7] visited: output: 0 1 3 7 4 5 2 6 Breadth First Search • Breadth First Search – It needs a queue to implement breadth-first search – void bfs(int v): breadth first traversal of a graph • starting with node v the global array visited is initialized to 0 • the queue operations are similar to those described in Chapter 18 struct queue { int node; queue * link; }; void addq(queue *, queue *, int); int deleteq(queue *); BFS - A Graphical Representation 0 a) 1 A B C D A B C D E F G H E F G H I J K L I J K L O P M N O P M 0 c) 0 N 1 2 b) 0 1 2 3 A B C D A B C D E F G H E F G H I J K L I J K L M N O P M N O P 29 d) More BFS 0 1 2 3 0 1 2 3 A B C D A B C D E F G H E F G H 4 4 I J K L I J K L M N O P M N O P 5 Breadth First Search : • Example [0] [1] [2] [3] [4] [5] [6] [7] visited: 0 1 2 3 4 5 6 7 out in output: 0 1 2 3 4 5 6 7 adjacency list: O(v+e) adjacency matrix: O(n2) w node w; queue front, rear; front=rear =NULL; /* initialize queue cout<<v; visited[v] = TURE; addq(&front, &rear, v); while (fornt) { v= deleteq(&front); for(w = graph[v]; w; w=w->link) if (!visited[w->node]) { cout<<w->node; addq(&front, &rear, w->node); node[w->node]=TRUE; } } Applications: Finding a Path • Find path from source node s to destination node d • Use graph search starting at s and terminating as soon as we reach d – Need to remember edges traversed • Use depth – first search ? • Use breath – first search? DFS vs. BFS DFS Process F B A G D C start E destination B DFS on B A DFS on A A G D B A C B A DFS on C D B A Call DFS on D Return to call on B Call DFS on G found destination - done! Path is implicitly stored in DFS recursion Path is: A, B, D, G DFS vs. BFS F B A G destination D C rear front E start BFS Process rear front rear front B D C Initial call to BFS on A Dequeue A Add A to queue Add B Dequeue B Add C, D A rear front G Dequeue D Add G found destination - done! Path must be stored separately rear front D Dequeue C Nothing to add Spanning trees • Connected components – If G is an undirected graph, then one can determine whether or not it is connected: • simply making a call to either dfs or bfs • then determining if there is any unvisited node Program: Connected components void connected ( ) { /* determine the connected components of a graph*/ int i; for (i=0; i<n ; i++) if( !visited[i]) { adjacency dfs(i); cout<<endl; adjacency } } list: O(n+e) matrix: O(n2) Spanning trees • Spanning trees – Definition: A tree T is said to be a spanning tree of a connected graph G if T is a subgraph of G and T contains all nodes of G. – E(G): T (tree edges) + N (nontree edges) • T: set of edges used during search • N: set of remaining edges Spanning trees • When graph G is connected, a depth first or breadth first search starting at any node will visit all nodes in G • We may use DFS or BFS to create a spanning tree – Depth first spanning tree when DFS is used – Breadth first spanning tree when BFS is used Spanning trees • Properties of spanning trees : – If a nontree edge (v, w) is introduced into any spanning tree T, then a cycle is formed. – A spanning tree is a minimal subgraph, G’, of G such that V(G’) = V(G) and G’ is connected. • We define a minimal subgraph as one with the fewest number of edge • A spanning tree has n-1 edges Biconnected Graph • Biconnected Graph & Articulation Points: • Assumption: G is an undirected, connected graph – Definition: A node v of G is an articulation point if the deletion of v, together with the deletion of all edges incident to v, leaves behind a graph that has at least two connected components. – Definition: A biconnected graph is a connected graph that has no articulation points. – Definition: A biconnected component of a connected graph G is a maximal biconnected subgraph H of G. • By maximal, we mean that G contains no other subgraph that is both biconnected and properly contains H. Biconnected Graph • Examples of Articulation Points (node 1, 3, 5, 7) 8 0 3 4 0 8 1 7 7 1 2 9 5 3 2 6 Connected graph 4 5 9 0 8 1 7 2 6 two connected components 3 4 9 5 6 one connected graph Biconnected Graph • Biconnected component: a maximal connected subgraph H – no subgraph that is both biconnected and properly contains H