Elementary Graph Algorithms [for graphs with no edge weights] Course: CS 5130 - Advanced Data Structures and Algorithms Instructor: Dr. Badri Adhikari
Representations of graph A directed or undirected graph G = (V, E) can be represented as (a) a collection of adjacency lists, or (b) an adjacency matrix. Adjacency-list representation provides a compact way to represent sparse graphs - those for which |E| is much less than |V 2 |. More common method. Adjacency-matrix representation is preferred (a) when the graph is dense - |E| is close to |V 2 |, or (b) when we need to be able to quickly tell if there is an edge connecting two given vertices.
Adjacency-list representation The adjacency-list representation of a graph G = (V, E) consists of an array Adj of |V| lists, one for each vertex. For each u ∈ V, the adjacency-list Adj [ u ] contains all the vertices v such that there is an edge ( u , v ) ∈ E. That is, Adj [ u ] consists of all the vertices adjacent to u in G. In pseudocodes, Adj is an attribute of G. For example, G. Adj [ u ]. array Adj
Adjacency-list representation If G is a directed graph, the sum of the lengths of all the adjacency lists is |E|, since and edge of the form ( u , v ) is represented by having v appear in Adj [ u ]. If G is undirected graph, the sum of the lengths of all the adjacency lists is 2 |E|, since if ( u , v ) is an undirected edge, then u appears in v ’s adjacency list and vice versa. For both directed and undirected graphs, the amount of memory required is Θ (V+E).
Adjacency-list representation Weighted graphs are the ones where each edge has an associated weight . Weight function w : E→R. We store the weight w ( u , v ) with vertex v in u ’s adjacency list. Disadvantage of adjacency-list representation: No quick way to determine whether a given edge ( u , v ) is present in the graph. The only way is to search for v in the list Adj [ u ].
Adjacency-matrix representation For adjacency-matrix representation of a graph G = (V, E), we assume that the vertices are numbered 1, 2, 3, …, |V| in some arbitrary manner. Then the adjacency-matrix representation of a graph G consists of a |V| x |V| matrix A = (a ij ) such that This representation requires Θ (V 2 ) memory, independent of the number of edges in the graph.
Adjacency-matrix representation For undirected graphs, the matrix is symmetrical , because ( u , v ) and ( v , u ) represent the same edge. For directed graphs, the matrix is unsymmetrical . In case of weighted graphs, we can simply store the weight w ( u , v ) as the entry in row u and column v of the adjacency matrix. If edge does not exist, NIL or 0 or ∞ may be stored. Adjacency matrix representations are simpler (although space inefficient), so for reasonably small graphs, they are preferred. Also, for unweighted graphs, they require only one bit per entry.
Classwork
Breadth-first search Given a graph G = (V, E) and a distinguished source vertex s , breadth-first search systematically explores the edges of G to ‘discover’ every vertex that is reachable from s . It computes the distance (smallest number of edges) from s to each reachable vertex. It also produces a ‘ breadth-first tree ’ with root s that contains all reachable vertices. In the breadth-first tree, a simple path from s to any vertex v corresponds to a ‘shortest path’ from s to v . It works on both directed and undirected graphs. It is so named because, it discovers all vertices at distance k from s before discovering any vertices at distance k + 1.
Breadth-first search (BFS) To keep track of progress, breadth-first search colors each vertex white, gray, or black. All vertices start out white ( undiscovered ), and then may become gray or black ( discovered ). BFS distinguishes between gray and black to ensure the search proceeds in a breadth-first manner. All vertices adjacent to black are either black or gray (i.e. discovered). Gray vertices may have some adjacent vertices white; they represent the frontier between discovered and undiscovered vertices.
Breadth-first search BFS constructs a breadth-first tree, initially containing only its root (source vertex s ). Start by scanning the adjacency list of the vertex s . (in an adjacency-list representation) When a white vertex v is found in the adjacency list, the vertex v and edge ( s , v ) are added to the tree. We say that s is a predecessor or parent of v in the breadth-first tree. Since a vertex is discovered at most once, it can have only one parent (at most). BFS uses first-in, first-out Queue.
Breadth-first search (initialization) (parent)
(parent)
Running time of BFS Initialization → O(V) Each vertex is enqueued at most once and dequeued at most once → O(V) The algorithm scans the adjacency-list of a vertex only when it is queued, so adjacency-lists are scanned only once. Total sum of all adjacency-lists is E. → O(E) Total running time → O(V + E). BFS runs in time linear in the size of the adjacency-list representation of G.
Breadth-first tree and shortest paths BFS builds a breadth-first tree as it searches the graph. The tree corresponds to the � attributes. Breadth-first tree (a predecessor subgraph ) of a graph G = (V, E) is G � = (V � , E � ) so that: V � = { v ∈ V : v . � ≠ NIL} U {s} E � = {( v . � , v ): v ∈ V � - {s}} The subgraph G � contains a unique simple path from s to v that is also a shortest path from s to v in G. Since G � is a connected tree, |E � | = |V � | - 1
Classwork Draw a Breadth-first tree for Chennai (C) What is the distance from C to each of the other cities? V � = { v ∈ V : v . � ≠ NIL} U {s} E � = {( v . � , v ): v ∈ V � - {s}}
Depth-first search The strategy is to search ‘deeper’ in the graph whenever possible. Unlike BFS, whose predecessor subgraph forms a tree, the predecessor subgraph produced by DFS may be composed of several trees (i.e. a depth-first forest ) → because the search may repeat from multiple sources. Predecessor subgraph of a graph G is G � = (V, E � ) and E � = {( v . � , v ): v ∈ V and v . � ≠ NIL}. As we search, we also record two timestamps - v . d (records when v is first discovered - grayed) and v . f (when v ’s adjacency list is finished examining - blackened). These timestamps are integers between 1 and 2|V|; and for every vertex u , u . d < u . f .
Depth-first search (DFS)
DFS
DFS
Running time of DFS Initialization takes Θ (V) time. Every edge (in the adjacency-list) is processed only once and sum of all |Adj[ v ]| is Θ (E). i.e. DFS-VISIT() needs Θ (E) time. Total DFS running time = Θ (V + E)
Classification of edges DFS can be used to classify the edges of the input graph G = (V, E). Tree edges are edges in the depth-first forest. A edge ( u , v ) in G is a back edge if v is ancestor of u in the depth-first forest. Forward edges are those nontree edges ( u , v ) connecting a vertex u to a descendant v in the depth-first tree. Cross edges are all other edges. They can go between vertices in the same tree or between vertices. Example application: A directed graph is acyclic if and only if a depth-first search yields no ‘back’ edges.
Classwork Run DFS for the graph below. Make following assumptions: (a) Vertices are considered alphabetically (not randomly) (b) Each adjacency list is sorted alphabetically (not randomly) 1. Show discovery and finish times for each vertex. 2. Show classification of each edge.
Topological sort A topological sort of a directed acyclic graph (DAG) G = (V, E) is a linear ordering of all its vertices such that if G contains an edge (u, v ), then u appears before v in the ordering. In applications that need topological sorting, directed acyclic graphs are used to indicate the precedences among events. a DAG showing precedences among events If a graph contains a cycle, no linear ordering is possible. Why? DFS can be used to perform topological sort.
Topological sort Say, A, B, C, D, E, and F are activities with dependencies shown below. Which is a topological sort, and which is not?
Topological sort TOPOLOGICAL-SORT(G) - Identify the vertices that have no incoming edges (say I is the set) - For each vertex in I, call DFS(G) and compute finish times v.f for each vertex - As each vertex’s finish time is computed, insert it onto the front of a linked list - Return the linked list of vertices Running time is Θ (V + E)
TOPOLOGICAL-SORT(G) Classwork - Identify the vertices that have no incoming edges (say I is the set) - For each vertex in I, call DFS(G) and compute finish times v.f for each vertex Show the ordering of vertices - As each vertex’s finish time is computed, insert it produced by TOPOLOGICAL-SORT() onto the front of a linked list when it is run on the following DAG. - Return the linked list of vertices Make following assumptions: (a) Vertices are considered alphabetically (not randomly) (b) Each adjacency list is sorted alphabetically (not randomly)
Recommend
More recommend