UNIT V
GRAPHS
Representation of Graphs – Breadth-first search – Depth-first search – Topological sort – Minimum
Spanning Trees – Kruskal and Prim algorithm – Shortest path algorithm – Dijkstra’s algorithm –
Bellman-Ford algorithm – Floyd - Warshall algorithm.
1. Briefly explain the details of Graph
A graph G = (V, E) consists of a set of vertices V and a set of edges E, such that each
edge in E is a connection between a pair of vertices in V. The number of vertices is written |V|,
and the number of edges is written |E|. |E| can range from zero to a maximum of
- |V|. A
graph with relatively few edges is called sparse, while a graph with many edges is called dense.
A graph containing all possible edges is said to be complete.
Types of Graph:
A graph with edges directed from one vertex to another is called a directed graph or
digraph.
A graph whose edges are not directed is called an undirected graph.
Properties of graph:
A graph with labels associated with its vertices is called a labeled graph.
Two vertices are adjacent if they are joined by an edge. Such vertices are also called
neighbors.
An edge connecting Vertices U and V is written (U, V). Such an edge is said to be
incident on Vertices U and V. Associated with each edge may be a cost or weight. Graphs
whose edges have weights are said to be weighted.
An undirected graph is connected if there is at least one path from any vertex to any
other. The maximally connected subgraphs of an undirected graph are called connected
components.
A digraph is strongly connected or strong if it contains a directed path from u to v and a
directed path from v to u for every pair of vertices u, v. The strong components are the
maximal strongly connected subgraphs.
A graph without cycles is called acyclic. Thus, a directed graph without cycles is called a
directed acyclic graph or DAG.
An n vertex undirected graph with exactly n(n-1)/2 edges is said to be complete graph.
The graph G is said to be complete graph.
A biconnected undirected graph is a connected graph that is not broken into
disconnected pieces by deleting any single vertex (and its incident edges).
A biconnected directed graph is one such that for any two vertices v and w there are
two directed paths from v to w which have no vertices in common other than v and w.
Representation of graph:
Adjacency Matrix
o The adjacency matrix data structure stores the adjacency matrix of the graph as a
2-dimensional Boolean array, where TRUE represents 1 (i.e., there is an edge)
and FALSE represents 0 (i.e., there is no edge). The main advantage of the
adjacency matrix representation is that for all vertices v and w we can check in
constant time whether or not there is an edge from vertex v to vertex w.
Adjacency List
o The adjacency list representation of a graph G with n vertices consists of an array
vertices with n entries, one for each vertex. The entry for vertex v is a list of all vertices
w such there is an edge from v to w. We make no assumptions on the order in which the
vertices adjacent to a vertex v appear in the adjacency list, and our algorithms should
work for any order.
Eg:
Adjacency Matrix representation of the graph is
Adjacency List representation of the graph is
2. Explain details about Breath First Search
A BFS starting at a vertex v rst visits v, then it visits all neighbours of v (i.e., all
vertices w such that there is an edge from v to w), then all neighbours of the neighbours that have
not been visited before, then all neighbours of the neighbours of the neighbours that have not
been visited before, et cetera. For example, a BFS of the graph in Figure, starting at vertex 0
would visit the vertices in the following order:
0, 2, 5, 4, 1
It first visits 0, then the neighbours 2; 5; 4 of 0. Next are the neighbours of 2, which are 1
and 5. Since 5 has been visited before, only 1 is added to the list. All neighbours of 5, 4, and 1
have already been visited, so we have found all vertices that are reachable from 0. Note that there
are other orders in which a BFS starting at 0 may visit the vertices of the graph, because the
neighbours of 0 may be visited in a different order. An example is 0, 5, 4, 2;,1. The vertices 3
and 6 are not reachable from 0, so we have to start another BFS, say at 3. It first visits 3 and then
6.
It is important to realise that the traversal heavily depends on the vertex we start at. For
example, if we start a BFS at vertex 6 it will visit all vertices in one sweep, maybe in the
following order:6, 5, 3, 1, 0, 2, 4:
Algorithm bfs(G)
1. Initialise Boolean array visited by setting all entries to FALSE
2. Initialise Queue Q
3. for all v 2 V do
4. if visited[v] = FALSE then
5. bfsFromVertex(G; v)
Algorithm bfsFromVertex(G; v)
1. visited[v] = TRUE
2. Q:enqueue(v)
3. while not Q:isEmpty() do
4. v Q:dequeue()
5. for all w adjacent to v do
6. if visited[w] = FALSE then
7. visited[w] = TRUE
8. Q:enqueue(w)
Other possible orders are 6, 3, 5, 1, 0, 2, 4 and 6, 5, 3, 1, 0, 4, 2 and 6, 3, 5, 1, 0, 4, 2.
3. Explain details about Depth First Search
A DFS starting at a vertex v first visits v, then some neighbour w of v, then some
neighbour x of w that has not been visited before, et cetera. Once it gets stuck, the DFS
backtracks until it finds the first vertex that still has a neighbour that has not been visited before.
It continues with this neighbour until it has to backtrack again. Eventually, it will visit all
vertices reachable from v. Then a new DFS is started at some vertex that is not reachable from v,
until all vertices have been visited. For example, a DFS in the graph of Figure, starting at 0 may
visit the vertices in the order: 0, 2, 1, 5, 4:
After it has visited 0, 2, 1 the DFS backtracks to 2, visits 5, then backtracks to 0, and
visits 4. A DFS starting at 0 might also visit the vertices in the order 0, 4, 5, 2, 1 or 0, 5, 4, 2, 1 or
0, 2, 5, 1, 4. As for BFS, this depends on the order in which the neighbours of a vertex are
processed. DFS can be implemented in a similar way as BFS using a Stack instead of a Queue,
see Algorithms dfs(G) and dfsFromVertex(G; v). There is also an elegant recursive
implementation of DFS.
Algorithm dfs(G)
1. Initialise Boolean array visited by setting all entries to FALSE
2. Initialise Stack S
3. for all v 2 V do
4. if visited[v] = FALSE then
5. dfsFromVertex(G; v)
Algorithm dfsFromVertex(G; v)
1. S:push(v)
2. while not S:isEmpty() do
3. v S:pop()
4. if visited[v] = FALSE then
5. visited[v] = TRUE
6. for all w adjacent to v do
7. S:push(w)
4. Explain details about Topological Sort
A Directed Acyclic Graph (DAG) is a directed graph without any cycles.
Given a DAG, the topological sorting problem is to find an ordering of the vertices such
that all edges go forward in the ordering. A typical situation where this problem comes up is
when you are given a set of tasks to do with precedence constraints (you need to do A and F
before you can do B, etc.), and you want to find a legal ordering for performing the jobs. We will
assume here that the graph is represented using an adjacency list.
One way to solve the topological sorting problem is to put all the nodes into a priority
queue according to in-degree. You then repeatedly pull out the node of minimum in-degree
(which should be zero — otherwise you output “graph is not acyclic”) and then decrement the
keys of each of its out-neighbors. Using a heap to implement the priority queue, this takes time
O(m log n). However, it turns out there is a better algorithm: a simple but clever O(m + n)-time
approach based on depth-first search.
To be specific, by a Depth-First Search (DFS) of a graph we mean the following
procedure. First, pick a node and perform a standard depth-first search from there. When that
DFS return, if the whole graphs have not yet been visited, pick the next unvisited node and
repeat the process. Continue until all vertices have been visited. Specifically, as pseudocode, we
have:
DFSmain(G):
For v=1 to n: if v is not yet visited, do DFS(v).
DFS(v):
mark v as visited. // entering node v
for each unmarked out-neighbor w of v: do DFS(w).
return. // exiting node v.
DFS takes time O(1 + out-degree(v)) per vertex v, for a total time of O(m + n). Here is now how
we can use this to perform a topological sorting:
1. Do depth-first search of G, outputting the nodes as you exit them.
2. Reverse the order of the list output in Step 1.
5. Explain details about minimum spanning tree
Suppose G=(V, E) is a connected graph in which each edge (u, v) in E has a cost c(u, v)
attached to it, A Spanning tree for G is a free tree that connects all the vertices in V. the cost of
spanning tree is the sum of the cost of edges in the tree.
A typical application for minimum-cost spanning trees occurs in the design of
communication networks. A minimum-cost spanning tree represents communication network
that connects all the cities at a minimal cost.
A tree is an undirected graph which is connected and acyclic. It is easy to show that if graph G(V,E) that
satisfies any two of the following properties also satisfies the third, and is therefore a tree:
• G(V,E) is connected
• G(V,E) is acyclic
• |E| = |V| −1
Direct applications: interconnection of entities.
1. electrical devices (circuit boards)
2. utilities (gas, oil)
3. computers or communication devices by high speed lines.
4. cable service customers
Indirect applications.
1. Optimal message passing.
2. Data storage.
3. Cluster analysis
o
It can by done in two ways of algorithms
o PRIM’S algorithm
o KRUSKAL algorithm
6. Write short notes on PRIM’S algorithm
Start with 1-vertex tree and grow it into an n-vertex tree by repeatedly adding a vertex
and an edge. When there is a choice, add a least cost edge.
Suppose V={1,2,…,n}, Prim’s algorithm begins with a set U initialized to {1}. It then
“grows” a spanning tree, one edge at a time. At each step, it finds a shortest edge (u, v) that
connects U and V-U and then adds v, the vertex in V-U, to U. It repeats this step until U=V.
Algorithm Prim(G(V,E), s)
v,w: vertices
dist: array[V] of integer
prev: array[V] of vertices
S: set of vertices, initially empty
H: priority heap of V
H := {s : 0}
for v ∈ V do
dist[v] := ∞, prev[v] :=nil
rof
dist[s] := 0
while H 6= 0/
v := deletemin(h)
S := S∪ {v}
for (v,w) ∈ E and w ∈ V −S do
if dist[w] > length(v,w)
dist[w] := length(v,w), prev[w] := v, insert(w,dist[w],H)
fi
rof
end while end Prim
Note that each vertex is “inserted” on the heap at most once; other insert operations simply
change the value on the heap. The vertices that are removed from the heap form the set S for the cut
property. The set X of edges chosen to be included in the MST are given by the parent pointers of the
vertices in the set S. Since the smallest key in the heap at any time gives the lightest edge crossing
between S and V −S, Prim’s algorithm follows the generic outline for a MST algorithm presented above,
and therefore its correctness follows from the cut property.
The running time of Prim’s algorithm is clearly the same as Dijkstra’s algorithm, since the only
change is how we prioritize nodes in the heap. Thus, if we use d-heaps, the running time of Prim’s
algorithm is O(mlogm/nn).
7. Write short notes on KRUSKAL algorithm
Given a connected graph G-(V, E), with V={1, 2, …, n} and a cost function c defined on edges of
E. Another way to construct a minimum-cost spanning tree for G is to start with graph T= (V, Ø)
consisting only of the n vertices of G and having no edges. Each vertex is therefore in connected
component by itself.
To build larger components, we examine edges from E, in order of increasing cost.
If the edge connects two vertices in two different connected components, then we add the edge to T.
If the edge connects two vertices in the same component, then we discard the edge, since it would
cause a cycle. When all vertices are in one component, T is a minimum-cost spanning tree for G.
To implement Kruskal’s algorithm, given a forest of trees, we must decide given two vertices whether
they belong to the same tree. For the purposes of this test, each tree in the forest can be represented by a
set consisting of the vertices in that tree. We also need to be able to update our data structure to reflect the
merging of two trees into a single tree. Thus our data structure will maintain a collection of disjoint sets
(disjoint since each vertex is in exactly one tree), and support the following three operations:
• MAKESET(x): Create a new x containing only the element x.
• FIND(x): Given an element x, which set does it belong to?
• UNION(x,y): replace the set containing x and the set containing y by their union.
The pseudocode for Kruskal’s algorithm follows:
Function Kruskal(graph G(V,E))
set X
X={}
E:= sort E by weight
for u ∈ V
MAKESET(u)
rof
for (u,v) ∈ E (in increasing order) do
if FIND(u) 6= FIND(v) do
X = X ∪ {(u,v)}
UNION(u,v)
rof
return(X)
end Kruskal
The correctness of Kruskal’s algorithm follows from the following argument: Kruskal’s
algorithm adds an edge e into X only if it connects two trees; let S be the set of vertices in one of these
two trees. Then e must be the first edge in the sorted edge list that has one endpoint in S and the other
endpoint in V − S, and is therefore the lightest edge that crosses between S and V −S. Thus the cut
property of MST implies the correctness of the algorithm.
The running time of the algorithm, assuming the edges are given in sorted order, is dominated by
the set operations: UNION and FIND. There are n−1 UNION operations (one corresponding to each edge
in the spanning tree), and 2m FIND operations (2 for each edge). Thus the total time of Kruskal’s
algorithm is O(m×FIND+ n × UNION). We will soon show that this is O(mlog*n). Note that, if the edges
are not initially given in sorted order, then to sort them in the obvious way takes O(mlogm) time, and this
would be the dominant part of the running time of the algorithm.
8. Write Short notes on Shortest Paths using Bellman-Ford Algorithm
Definition:(Shortest Path)
Given a weighted, directed graph G, a start node s and a destination node t, the s-t shortest path
problem is to output the shortest path from s to t. The single-source shortest path problem is to find
shortest paths from s to every node in G. The (algorithmically equivalent) single-sink shortest path
problem is to find shortest paths from every node in G to t.
Shortest Paths using Bellman-Ford Algorithm
The BellmanFord algorithm is a Dynamic Programming algorithm that solves the shortest path
problem. It looks at the structure of the graph, and iteratively generates a better solution until it reaches
the best solution. BellmanFord can handle negative weights readily, because it uses the entire graph to
improve a solution.
A Dynamic Programming algorithm called the Bellman-Ford Algorithm for the single-sink (or singlesource) shortest path problem. Let us develop the algorithm using the following example:
How can we use Dyanamic Programming to find the shortest path from all nodes to t? First of all, as usual
for Dynamic Programming, let’s just compute the lengths of the shortest paths first, and afterwards we
can easily reconstruct the paths themselves. The idea for the algorithm is as follows:
o
o
o
For each node v, find the length of the shortest path to t that uses at most 1 edge, or write down ∞
if there is no such path. This is easy: if v = t we get 0; if (v,t) ∈ E then we get len(v,t); else just
put down ∞.
Now, suppose for all v we have solved for length of the shortest path to t that uses i − 1 or fewer
edges. How can we use this to solve for the shortest path that uses i or fewer edges?
Answer: the shortest path from v to t that uses i or fewer edges will first go to some neighbor x of
v, and then take the shortest path from x to t that uses i−1 or fewer edges, which we’ve already
solved for! So, we just need to take the min over all neighbors x of v.
How far do we need to go? Answer: at most i = n − 1 edges.
Specifically, here is pseudocode for the algorithm. We will use d[v][i] to denote the length of the shortest
path from v to t that uses i or fewer edges (if it exists) and infinity otherwise (“d” for “distance”). Also,
for convenience we will use a base case of i = 0 rather than i = 1.
Bellman-Ford pseudocode:
initialize d[v][0] = infinity for v != t. d[t][i]=0 for all i.
for i=1 to n-1:
for each v != t:
d[v][i] = min(len(v,x) + d[x][i-1])
(v,x)∈E
For each v, output d[v][n-1].
The min operation takes time proportional to the out-degree of v. So, the inner for-loop takes time
proportional to the sum of the out-degrees of all the nodes, which is O(m). Therefore, the total time is
O(mn).
9. Write Short notes on Shortest Paths using Dijkstra’s Algorithm
Definition:(Shortest Path)
Given a weighted, directed graph G, a start node s and a destination node t, the s-t shortest path
problem is to output the shortest path from s to t. The single-source shortest path problem is to find
shortest paths from s to every node in G. The (algorithmically equivalent) single-sink shortest path
problem is to find shortest paths from every node in G to t.
Dijkstra’s Algorithm:
Input: Graph G, with each edge e having a length len(e), and a start node s.
Initialize: tree = {s}, no edges. Label s as having distance 0 to itself.
Invariant: nodes in the tree are labeled with the correct distance to s.
Repeat:
1. For each neighbor x of the tree, compute an (over)-estimate of its distance to s:
In other words, by our invariant, this is the length of the shortest path to x whose only
edge not in the tree is the very last edge.
2. 2. Insert the node x of minimum distance into tree, connecting it via the argmin (the edge e used
to get distance(x) in the expression.
Let us run the algorithm on the following example starting from vertex A:
Running time:
To implement this efficiently, rather than recomputing the distances every time in step 1, you simply want
to update the ones that actually are affected when a new node is added to the tree in step 2, namely the
neighbors of the node added. If you use a heap data structure to store the neighbors of the tree, you can
get a running time of O(m log n). In particular, you can start by giving all nodes a distance of infinity
except for the start with a distance of 0, and putting all nodes into a min-heap. Then, repeatedly pull off
the minimum and update its neighbors, tentatively assigning parents whenever the distance of some node
is lowered. It takes linear time to initialize the heap, and then we perform m updates at a cost of O(log n)
each for a total time of O(m log n).
10.
Write short notes on The Floyd-Warshall Algorithm
The Floyd-Warshall Algorithm is an algorithm for the all pairs shortest paths problem that works
completely differently than the BFS-based algorithm.
Let G = (V, E) be a graph with vertices numbered 0 to n -1. We will identify vertices with their
numbers. In other words, we assume that V = {0, . . . , n - 1}. To explain how the algorithm works, it is
best to consider the problem of computing the distance matrix of G first, i.e., the matrix D =
(dij)0<=i,j<=n-1 with dij being the distance from vertex i to vertex j.
Algorithm bfsSSSP(G; v)
1. Initialise array distance by setting all entries to 1
2. Initialise array parent by setting all entries to NIL
3. Initialise Queue Q
4. distance[v] = 0
5. Q:enqueue(v)
6. while not Q:isEmpty() do
7. v Q:dequeue()
8. for all w adjacent to v do
9. if distance[w] = 1 then
10. parent[w] = v
11. distance[w] = distance[v] + 1
12. Q:enqueue(w)
13. return parent
We first consider a simple but inef cient matrix based algorithm for the problem of computing a
distance matrix. For 0 <= i; j <= n - 1 and k >= 0, let
The Floyd-Warshall algorithm uses a beautiful trick to make essentailly the same idea work faster. The
interior vertices of a path are all its vertices except the two endpoints
© Copyright 2026 Paperzz