Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
69 views

Assignment 2

The document discusses graph data structures and algorithms for traversing graphs. It defines key graph terms like vertices, edges, adjacency, and paths. It describes representations of graphs using adjacency matrices and incidence matrices. It explains breadth-first search (BFS) and depth-first search (DFS) algorithms for traversing graphs, including the steps and rules of each algorithm. It also provides an overview of Dijkstra's algorithm for finding the shortest path between nodes in a graph.

Uploaded by

Yusra Gulfam
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
69 views

Assignment 2

The document discusses graph data structures and algorithms for traversing graphs. It defines key graph terms like vertices, edges, adjacency, and paths. It describes representations of graphs using adjacency matrices and incidence matrices. It explains breadth-first search (BFS) and depth-first search (DFS) algorithms for traversing graphs, including the steps and rules of each algorithm. It also provides an overview of Dijkstra's algorithm for finding the shortest path between nodes in a graph.

Uploaded by

Yusra Gulfam
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 33

COMSATS University Islamabad Abbottabad, Pakistan

ASSIGNMENT 4:

DATA STRUCTURE

SUBBMITTED BY:

YUSRA GULFAM
SP21-BCS-065

SUBMITTED TO :
SIR DR.IMRAN ALI KHAN

Date:
02/01/23
Graph Data Structure
A graph is a pictorial representation of a set of objects where some pairs
of objects are connected by links. The interconnected objects are
represented by points termed as vertices, and the links that connect the
vertices are called edges.

Graph Data Structure


We can represent a graph using an array of vertices and a two-
dimensional array of edges. Before we proceed further, let's familiarize
ourselves with some important terms
 Vertex − Each node of the graph is represented as a vertex.
In the following example, the labeled circle represents
vertices. Thus, A to G are vertices. We can represent them
using an array as shown in the following image. Here A can
be identified by index 0. B can be identified using index 1 and
so on.
 Edge − Edge represents a path between two vertices or a
line between two vertices. In the following example, the lines
from A to B, B to C, and so on represents edges. We can use
a two-dimensional array to represent an array as shown in
the following image. Here AB can be represented as 1 at row
0, column 1, BC as 1 at row 1, column 2 and so on, keeping
other combinations as 0.
 Adjacency − Two node or vertices are adjacent if they are
connected to each other through an edge. In the following
example, B is adjacent to A, C is adjacent to B, and so on.
 Path − Path represents a sequence of edges between the
two vertices. In the following example, ABCD represents a
path from A to D.

Representation of Graphs in Data Structures

The most frequent graph representations are that follow:


 Adjacency matrix

 Incidence Matrix

 Adjacency list

Adjacency Matrix
 A sequential representation is an adjacency matrix.

 It's used to show which nodes are next to one another. I.e.,
is there any connection between nodes in a graph?

 You create an MXM matrix G for this representation. If an


edge exists between vertex a and vertex b, the
corresponding element of G, gi,j = 1, otherwise gi,j = 0.

 If there is a weighted graph, you can record the edge's


weight instead of 1s and 0s.

Undirected Graph Representation

Directed Graph Representation


Weighted Undirected Graph Representation 

Weight or cost is indicated at the graph's edge, a weighted graph


representing these values in the matrix.

Incidence Matrix
In this representation, graph can be represented using a matrix of size
total number of vertices by total number of edges. That means if a graph
with 4 vertices and 6 edges can be represented using a matrix of 4X6
class. In this matrix, rows represents vertices and columns represents
edges. This matrix is filled with either 0 or 1 or -1. Here, 0 represents row
edge is not connected to column vertex, 1 represents row edge is
connected as outgoing edge to column vertex and -1 represents row
edge is connected as incoming edge to column vertex.
Traversal Techniques
Breadth First Search (BFS)

Breadth First Search (BFS) algorithm traverses a graph in a breadthward


motion and uses a queue to remember to get the next vertex to start a
search, when a dead end occurs in any iteration.

As in the example given above, BFS algorithm traverses from A to B to E


to F first then to C and G lastly to D. It employs the following rules.
 Rule 1 − Visit the adjacent unvisited vertex. Mark it as
visited. Display it. Insert it in a queue.
 Rule 2 − If no adjacent vertex is found, remove the first
vertex from the queue.
 Rule 3 − Repeat Rule 1 and Rule 2 until the queue is empty.

Step Traversal Description

Initialize the queue.


2

We start from
visiting S (starting node), and
mark it as visited.

3
We then see an unvisited
adjacent node from S. In this
example, we have three
nodes but alphabetically we
choose A, mark it as visited
and enqueue it.

Next, the unvisited adjacent


node from S is B. We mark it
as visited and enqueue it.

Next, the unvisited adjacent


node from S is C. We mark it
as visited and enqueue it.
6

Now, S is left with no


unvisited adjacent nodes. So,
we dequeue and find A.

From A we have D as
unvisited adjacent node. We
mark it as visited and
enqueue it.

At this stage, we are left with no unmarked (unvisited) nodes. But as per
the algorithm we keep on dequeuing in order to get all unvisited nodes.
When the queue gets emptied, the program is over.

Depth First Search (DFS)

Depth First Search (DFS) algorithm traverses a graph in a depthward


motion and uses a stack to remember to get the next vertex to start a
search, when a dead end occurs in any iteration.
As in the example given above, DFS algorithm traverses from S to A to
D to G to E to B first, then to F and lastly to C. It employs the following
rules.
 Rule 1 − Visit the adjacent unvisited vertex. Mark it as
visited. Display it. Push it in a stack.
 Rule 2 − If no adjacent vertex is found, pop up a vertex from
the stack. (It will pop up all the vertices from the stack, which
do not have adjacent vertices.)
 Rule 3 − Repeat Rule 1 and Rule 2 until the stack is empty.
Step Traversal Description

Initialize the stack.

2
Mark S as visited and put it
onto the stack. Explore any
unvisited adjacent node
from S. We have three nodes
and we can pick any of them.
For this example, we shall
take the node in an
alphabetical order.

3
Mark A as visited and put it
onto the stack. Explore any
unvisited adjacent node from
A. Both S and D are adjacent
to A but we are concerned for
unvisited nodes only.
4
Visit D and mark it as visited
and put onto the stack. Here,
we have B and C nodes,
which are adjacent to D and
both are unvisited. However,
we shall again choose in an
alphabetical order.

We choose B, mark it as
visited and put onto the stack.
Here B does not have any
unvisited adjacent node. So,
we pop B from the stack.

6
We check the stack top for
return to the previous node
and check if it has any
unvisited nodes. Here, we
find D to be on the top of the
stack.

Only unvisited adjacent node


is from D is C now. So we
visit C, mark it as visited and
put it onto the stack.

As C does not have any unvisited adjacent node so we keep popping


the stack until we find a node that has an unvisited adjacent node. In this
case, there's none and we keep popping until the stack is empty.
Dijkstra's Algorithm
Dijkstra's algorithm, published in 1959, is named after its discoverer
Edsger Dijkstra, who was a Dutch computer scientist. This algorithm
aims to find the shortest-path in a directed or undirected graph with non-
negative edge weights.

Dijkstra’s algorithm is the iterative algorithmic process to provide us with


the shortest path from one specific starting node to all other nodes of a
graph. It is different from the minimum spanning tree as the shortest
distance among two vertices might not involve all the vertices of the
graph.

It is important to note that Dijkstra’s algorithm is only applicable when all


weights are positive because, during the execution, the weights of the
edges are added to find the shortest path

Dijkstra algorithm
1. The very first step is to mark all nodes as unvisited,
2. Mark the picked starting node with a current distance of 0 and the
rest nodes with infinity, 
3. Now, fix the starting node as the current node,
4. For the current node, analyse all of its unvisited neighbours and
measure their distances by adding the current distance of the
current node to the weight of the edge that connects the neighbour
node and current node,
5. Compare the recently measured distance with the current distance
assigned to the neighbouring node and make it as the new current
distance of the neighbouring node,
6. After that, consider all of the unvisited neighbours of the current
node, mark the current node as visited,
7. If the destination node has been marked visited then stop, an
algorithm has ended, and
8. Else, choose the unvisited node that is marked with the least
distance, fix it as the new current node, and repeat the process
again from step 4.

Example of Dijkstra's Algorithm


  
We will calculate the shortest path between node C and the other nodes
in the graph.

1. During the execution of the algorithm, each node will be marked


with its minimum distance to node C as we have selected node C. 
  In this case, the minimum distance is 0 for node C. Also, for the rest of
the nodes, as we don’t know this distance, they will be marked as infinity
(∞), except node C (currently marked as red dot).
Graphical Representation of Node C as Current Node

Now the neighbours of node C will be checked, i.e, node A, B, and D.


We start with B, here we will add the minimum distance of current node
(0) with the weight of the edge (7) that linked the node C to node B and
get 0+ 7= 7.
 
Now, this value will be compared with the minimum distance of B
(infinity), the least value is the one that remains the minimum distance of
B, like in this case, 7 is less than infinity, and marks the least value to
node B.

Assign Node B a minimum distance value


3. Now, the same process is checked with neighbour A. We add 0
with 1 (weight of edge that connects node C to A), and get 1.
Again, 1 is compared with the minimum distance of A (infinity), and
marks the lowest value.
 
Assign Node A  a minimum distance value
The same is repeated with node D, and marked 2 as lowest value
at D.

Assign Node D a minimum distance value


Since, all the neighbours of node C have checked, so node C is
marked as visited with a green check mark.
 

Marked Node C as visited 


4. Now, we will select the new current node such that the node must
be unvisited with the lowest minimum distance, or the node with
the least number and no check mark. Here, node A is the unvisited
with minimum distance 1, marked as current node with red dot. 

Graphical Representation of Node A  as Current Node


We repeat the algorithm, checking the neighbour of the current
node while ignoring the visited node, so only node B will be
checked.
For node B, we add 1 with 3 (weight of the edge connecting node A
to B) and obtain 4. This value, 4, will be compared with the
minimum distance of B, 7, and mark the lowest value at B as 4. 

Assign Node  B  a minimum distance value


5. After this, node A marked as visited with a green check mark. The
current node is selected as node D, it is unvisited and has a
smallest recent distance. We repeat the algorithm and check for
node B and E.
 

Graphical Representation of Node D  as Current Node


For node B, we add 2 to 5, get 7 and compare it with the minimum
distance value of B, since 7>4, so leave the smallest distance value
at node B as 4. 
For node E, we obtain 2+ 7= 9, and compare it with the minimum
distance of E which is infinity, and mark the smallest value as node
E as 9. The node D is marked as visited with a green check mark.

Marked Node  D as visited


6. The current node is set as node B, here we need to check only
node E as it is unvisited and the node D is visited. We obtain 4+
1=5, compare it with the minimum distance of the node.
As 9 > 5, leave the smallest value at node node E as 5.
 
We mark D as visited node with a green check mark, and node E is
set as the current node.

Marked Node  B  as visited


7. Since it doesn’t have any unvisited neighbours, so there is not any
requirement to check anything. Node E is marked as a visited
node with a green mark.

Marked Node E  as visited

So, we are done as no unvisited node is left. The minimum distance of


each node is now representing the minimum distance of that node from
node C.
Implementation of Dijkstra Algorithm in JAVA

import java.util.*;

import java.lang.*;

import java.io.*;

class dijkstra_algo {

//Function to find the vertex with minimum distance

static final int n = 6;//size of grap

int min_dist(int distance[], Boolean visited[])

int min = Integer.MAX_VALUE, min_index = -1;

for (int v = 0; v < n; v++)

if (visited[v] == false && distance[v] <= min) {

min = distance[v];

min_index = v;

return min_index;

//Function to print the constructed distance array

void printSolution(int distance[], int n)

System.out.println("Vertex Distance from Source");

for (int i = 0; i < n; i++)

System.out.println(((char)(i+65)) + " \t\t \t" + distance[i]);

}
// Function that implements Dijkstra's algorithm

void dijkstra(int graph[][], int source)

int distance[] = new int[n]; // The output array

Boolean visited[] = new Boolean[n];

// Initialize all distances as INFINITE and stpSet[] as false

for (int i = 0; i < n; i++) {

distance[i] = Integer.MAX_VALUE;//initializing infinity

visited[i] = false;

// Distance of source vertex from itself is always 0

distance[source] = 0;

// Find shortest path for all vertices

for (int count = 0; count < n - 1; count++) {

// Pick the minimum distance vertex from unvisited vertices

int u = min_dist(distance, visited);

// Mark the picked vertex as visited

visited[u] = true;

// Updating dist value of the adjacent vertices of the

// picked vertex.

for (int v = 0; v < n; v++)

//relaxing all the neighbouring vertices

if (!visited[v] && graph[u][v] != 0 &&

distance[u] != Integer.MAX_VALUE && distance[u] + graph[u][v] <


distance[v])

distance[v] = distance[u] + graph[u][v];


}

// print the constructed distance array

printSolution(distance, n);

// Driver method

public static void main(String[] args)

{ int graph[][] = new int[][] { {0,4,5,0,0,0},

{4,0,11,9,7,0},

{5,11,0,0,3,0},

{0,9,0,0,13,2},

{0,7,3,13,0,6},

{0,0,0,2,6,0}};

dijkstra_algo t = new dijkstra_algo();

int src=0;

t.dijkstra(graph, src);

Output for Above Code

Vertex Distance from Source

A 0

B 4

C 5

D 13

E 8

F 14
Prim’s Algorithm
 Prim’s Algorithm is a famous greedy algorithm.
 It is used for finding the Minimum Spanning Tree (MST) of a given
graph.
 To apply Prim’s algorithm, the given graph must be weighted,
connected and undirected.
 
 

Prim’s Algorithm Implementation


  

 Step-01:
Randomly choose any vertex.
The vertex connecting to the edge having least weight is usually
selected
.
 
Step-02:
 
 Find all the edges that connect the tree to new vertices.
 Find the least weight edge among those edges and include it in the
existing tree.
 If including that edge creates a cycle, then reject that edge and
look for the next least weight edge.
 Step-03:
 Keep repeating step-02 until all the vertices are included and
Minimum Spanning Tree (MST) is obtained.

 Primarily, to begin with the creation of MST, you will choose an


arbitrary starting vertex. Let’s say node A is your starting vertex.
This means it will be included first in your tree structure.
 After the inclusion of node A, you will look into the connected
edges going outward from node A and you will pick the one with
a minimum edge weight to include it in your T(V’, E’) structure. 

 Now, you have reached node B. From node B, there are two
possible edges out of which edge BD has the least edge weight
value. So, you will include it in your MST. 
 From node D, you only have one edge. So, you will include it in
your MST. Further, you have node H, for which you have two
incident edges. Out of those two edges, edge HI has the least
cost, so you will include it in MST structure.

 Similarly, the inclusion of nodes G and E will happen in MST. 

 After that, nodes E and C will get included. Now, from node C,
you have two incident edges. Edge CA has the tiniest edge
weight. But its inclusion will create a cycle in a tree structure,
which you cannot allow. Thus, we will discard edge CA as
shown in the image below.

 And we will include edge CF in this minimum spanning tree


structure. 

 The summation of all the edge weights in MST T(V’, E’) is equal
to 30, which is the least possible edge weight for any possible
spanning tree structure for this particular graph. 

Java Prim’s minimum spanning tree algorithm

import java.util.ArrayList;
• import java.util.Arrays;
• import java.util.List;
• import java.util.Collections;
• import java.util.PriorityQueue;
• import java.util.Comparator;

• class NodeCost {

• int node; // Adjacent node
• int cost; // Costance/cost to adjacent node

• NodeCost (int node, int cost) {
• this.node = node;
• this.cost = cost;
• }
• }

• class Prims {

• int Find_MST(int source_node, List<List<NodeCost>> graph) {

• // Comparator lambda function that enables the priority queue to
store the nodes
• // based on the cost in the ascending order.
• Comparator<NodeCost> NodeCostComparator = (obj1, obj2) -> {
• return obj1.cost - obj2.cost;
• };

• // Priority queue stores the object node-cost into the queue with
• // the smallest cost node at the top.
• PriorityQueue<NodeCost> pq = new
PriorityQueue<>(NodeCostComparator);

• // The cost of the source node to itself is 0
• pq.add(new NodeCost(source_node, 0));

• boolean added[] = new boolean[graph.size()];
• Arrays.fill(added, false);

• int mst_cost = 0;

• while (!pq.isEmpty()) {

• // Select the item <node, cost> with minimum cost
• NodeCost item = pq.peek();
• pq.remove();

• int node = item.node;
• int cost = item.cost;

• // If the node is node not yet added to the minimum spanning
tree, add it and increment the cost.
• if ( !added[node] ) {
• mst_cost += cost;
• added[node] = true;

• // Iterate through all the nodes adjacent to the node taken out
of priority queue.
• // Push only those nodes (node, cost) that are not yet present
in the minumum spanning tree.
• for (NodeCost pair_node_cost : graph.get(node)) {
• int adj_node = pair_node_cost.node;
• if (added[adj_node] == false) {
• pq.add(pair_node_cost);
• }
• }
• }
• }
• return mst_cost;
• }

• public static void main(String args[]) {

• Prims p = new Prims();

• int num_nodes = 6; // Nodes (0, 1, 2, 3, 4, 5)

• List<List<NodeCost>> graph_1 = new ArrayList<>(num_nodes);
• for (int i=0; i < num_nodes; i++) {
• graph_1.add(new ArrayList<>());
• }

• // Node 0
• Collections.addAll(graph_1.get(0), new NodeCost(1, 4), new
NodeCost(2, 1), new NodeCost(3, 5));
• // Node 1
• Collections.addAll(graph_1.get(1), new NodeCost(0, 4), new
NodeCost(3, 2), new NodeCost(4, 3),
• new NodeCost(5, 3));
• // Node 2
• Collections.addAll(graph_1.get(2), new NodeCost(0, 1), new
NodeCost(3, 2), new NodeCost(4, 8));
• // Node 3
• Collections.addAll(graph_1.get(3), new NodeCost(0, 5), new
NodeCost(1, 2), new NodeCost(2, 2),
• new NodeCost(4, 1));
• // Node 4
• Collections.addAll(graph_1.get(4), new NodeCost(1, 3), new
NodeCost(2, 8), new NodeCost(3, 1),
• new NodeCost(5, 4));
• // Nod

• e5
• Collections.addAll(graph_1.get(5), new NodeCost(1, 3), new
NodeCost(4, 4));

• // Start adding nodes to minimum spanning tree with 0 as the
souce node
• System.out.println("Cost of the minimum spanning tree in graph
1 : " + p.Find_MST(0, graph_1));

• // Outgoing edges from the node:<cost, adjacent_node> in graph
2.
• num_nodes = 7; // Nodes (0, 1, 2, 3, 4, 5, 6)

• List<List<NodeCost>> graph_2 = new ArrayList<>(num_nodes);
• for (int i=0; i < num_nodes; i++) {
• graph_2.add(new ArrayList<>());
• }

• // Node 0
• Collections.addAll(graph_2.get(0), new NodeCost(1, 1), new
NodeCost(2, 2), new NodeCost(3, 1),
• new NodeCost(4, 1), new NodeCost(5, 2),
new NodeCost(6, 1));
• // Node 1
• Collections.addAll(graph_2.get(1), new NodeCost(0, 1), new
NodeCost(2, 2), new NodeCost(6, 2));
• // Node 2
• Collections.addAll(graph_2.get(2), new NodeCost(0, 2), new
NodeCost(1, 2), new NodeCost(3, 1));
• // Node 3
• Collections.addAll(graph_2.get(3), new NodeCost(0, 1), new
NodeCost(2, 1), new NodeCost(4, 2));
• // Node 4
• Collections.addAll(graph_2.get(4), new NodeCost(0, 1), new
NodeCost(3, 2), new NodeCost(5, 2));
• // Node 5
• Collections.addAll(graph_2.get(5), new NodeCost(0, 2), new
NodeCost(4, 2), new NodeCost(6, 1));
• // Node 6
• Collections.addAll(graph_2.get(6), new NodeCost(0, 1), new
NodeCost(1, 2), new NodeCost(5, 1));


• // Start adding nodes to minimum spanning tree with 0 as the
souce node
• System.out.println("Cost of the minimum spanning tree in graph
2 : " + p.Find_MST(0, graph_2));
• }
• }
Output
• Cost of the minimum spanning tree in graph 1 : 9
• Cost of the minimum spanning tree in graph 2 : 6

Kruskal's Algorithm
Kruskal's algorithm is a greedy algorithm in graph theory that finds a
minimum spanning tree for a connected weighted graph.
It finds a subset of the edges that forms a tree that includes every vertex,
where the total weight of all the edges in the tree is minimized.
This algorithm is directly based on the MST( minimum spanning tree)
property.

Kruskal's algorithm
It falls under a class of algorithms called greedy algorithms that find the
local optimum in the hopes of finding a global optimum.
We start from the edges with the lowest weight and keep adding edges
until we reach our goal.

The steps for implementing Kruskal's algorithm are as follows:

1. Sort all the edges from low weight to high

2. Take the edge with the lowest weight and add it to the spanning
tree. If adding the edge created a cycle, then reject this edge.

3. Keep adding edges until we reach all vertices.

Example of Kruskal's algorithm


Start with a weighted graph

Choose the edge with the least weight, if there are more than 1, choose
anyone
Choose the next shortest edge and add it

Choose the next shortest edge that doesn't create a cycle and add it

Choose the next shortest edge that doesn't create a cycle and add it

Repeat until you have a spanning tree


Java Kruskal’s Code

import java.util.*;

class Graph {
class Edge implements Comparable<Edge> {
int src, dest, weight;

public int compareTo(Edge compareEdge) {


return this.weight - compareEdge.weight;
}
};

// Union
class subset {
int parent, rank;
};

int vertices, edges;


Edge edge[];

// Graph creation
Graph(int v, int e) {
vertices = v;
edges = e;
edge = new Edge[edges];
for (int i = 0; i < e; ++i)
edge[i] = new Edge();
}

int find(subset subsets[], int i) {


if (subsets[i].parent != i)
subsets[i].parent = find(subsets, subsets[i].parent);
return subsets[i].parent;
}

void Union(subset subsets[], int x, int y) {


int xroot = find(subsets, x);
int yroot = find(subsets, y);

if (subsets[xroot].rank < subsets[yroot].rank)


subsets[xroot].parent = yroot;
else if (subsets[xroot].rank > subsets[yroot].rank)
subsets[yroot].parent = xroot;
else {
subsets[yroot].parent = xroot;
subsets[xroot].rank++;
}
}

// Applying Krushkal Algorithm


void KruskalAlgo() {
Edge result[] = new Edge[vertices];
int e = 0;
int i = 0;
for (i = 0; i < vertices; ++i)
result[i] = new Edge();

// Sorting the edges


Arrays.sort(edge);
subset subsets[] = new subset[vertices];
for (i = 0; i < vertices; ++i)
subsets[i] = new subset();
for (int v = 0; v < vertices; ++v) {
subsets[v].parent = v;
subsets[v].rank = 0;
}
i = 0;
while (e < vertices - 1) {
Edge next_edge = new Edge();
next_edge = edge[i++];
int x = find(subsets, next_edge.src);
int y = find(subsets, next_edge.dest);
if (x != y) {
result[e++] = next_edge;
Union(subsets, x, y);
}
}
for (i = 0; i < e; ++i)
System.out.println(result[i].src + " - " + result[i].dest + ": " + result[i].weight);
}

public static void main(String[] args) {


int vertices = 6; // Number of vertices
int edges = 8; // Number of edges
Graph G = new Graph(vertices, edges);

G.edge[0].src = 0;
G.edge[0].dest = 1;
G.edge[0].weight = 4;

G.edge[1].src = 0;
G.edge[1].dest = 2;
G.edge[1].weight = 4;
G.edge[2].src = 1;
G.edge[2].dest = 2;
G.edge[2].weight = 2;

G.edge[3].src = 2;
G.edge[3].dest = 3;
G.edge[3].weight = 3;

G.edge[4].src = 2;
G.edge[4].dest = 5;
G.edge[4].weight = 2;

G.edge[5].src = 2;
G.edge[5].dest = 4;
G.edge[5].weight = 4;

G.edge[6].src = 3;
G.edge[6].dest = 4;
G.edge[6].weight = 3;

G.edge[7].src = 5;
G.edge[7].dest = 4;
G.edge[7].weight = 3;
G.KruskalAlgo();
}
}

You might also like