0% found this document useful (0 votes)
12 views19 pages

DAA Practical Jinesh

Uploaded by

jainnjinesh2312
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views19 pages

DAA Practical Jinesh

Uploaded by

jainnjinesh2312
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

A

Practical File
On

Design and Analysis of Algorithms Lab


Submitted In Partial Fulfilment of the requirements for the award of degree of
Bachelor of Technology
In
Computer Science & Engineering
From

Engineering College Bikaner

Affiliated to

Bikaner Technical University, Bikaner


(Session:2021- 2025)

Submitted by : Submitted to :
Jinesh Jain Mr. Rishiraj Vyas
Roll no.: Assistant Professor
21EEBCS052 (Department of CSE)
INDEX

S.N Name of Practical Date Signature

1 Sort a given set of elements using the Quicksort method and determine the time required to sort the
elements. Repeat the experiment for different values of n, the number of elements in the list to be
sorted and plot a graph of the time taken versus n. The elements can be read from a file or can be
generated using the random number generator.

2 Implement a parallelized Merge Sort algorithm to sort a given set of elements and determine the
time required to sort the elements. Repeat the experiment for different values of n, the number of
elements in the list to be sorted and plot a graph of the time taken versus n. The elements can be
read from a file or can be generated using the random number generator.

3 a. Obtain the Topological ordering of vertices in a given digraph.


b. Compute the transitive closure of a given directed graph using Warshall's algorithm.

4 Implement 0/1 Knapsack problem using Dynamic Programming.

5 F om a givenve texin a weighte


Dijkst a's algo ithm.
connecte g aph, fin sho test pathsto othe ve tices using

6 Find Minimum Cost Spanning Tree of a given undirected graph using Kruskal's algorithm.

7 a. Print all the nodes reachable from a given starting node in a digraph using BFS method.
b. Check whether a given graph is connected or not using DFS method.

8 Find Minimum Cost Spanning Tree of a given undirected graph using Prim’s algorithm.
Q1.
a.] Sort a given set of elements using the Quicksort method
and determine the time required to sort the elements.

ANS.

import random
import time
import matplotlib.pyplot as plt

def quicksort(arr):
#quicksort Function: Implements the Quicksort algorithm recursively.
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quicksort(left) + middle + quicksort(right)

def measure_time_quicksort(arr):
#measure_time_quicksort Function: Measures the time taken to sort an array
using Quicksort.

start_time = time.time()
quicksort(arr)
end_time = time.time()
return end_time - start_time

# Generate random lists and measure time

list_sizes = [100, 500, 1000, 5000, 10000, 50000, 100000, 200000]


times = []

for size in list_sizes:


arr = random.sample(range(size * 10), size)
time_taken = measure_time_quicksort(arr)
times.append(time_taken)
# Plot the results

plt.plot(list_sizes, times, marker='o')


plt.title('Quicksort Time Complexity')
plt.xlabel('Number of Elements (n)')
plt.ylabel('Time Taken (seconds)')
plt.grid(True)
plt.show()

list_sizes, times

b.] Repeat the experiment for different values of n, the


number of elements in the list to be sorted and plot a graph of the
time taken versus n. The elements can be read from a file or can be
generated using the random number generator.

ANS.

([100, 500, 1000, 5000, 10000, 50000, 100000, 200000],


[0.0002002716064453125, 0.0011584758758544922, 0.0019605159759521484,
0.011060714721679688, 0.024227142333984375, 0.14590120315551758,
0.3514833450317383, 0.8221611976623535]
)

 For 100 elements: 0.0002 seconds


 For 500 elements: 0.0012 seconds
 For 1000 elements: 0.0020 seconds
 For 5000 elements: 0.0111 seconds
 For 10000 elements: 0.0242 seconds
 For 50000 elements: 0.1459 seconds
 For 100000 elements: 0.3515 seconds
 For 200000 elements: 0.8222 seconds

The plot shows that the time complexity of Quicksort is approximately O(nlogn),
which is evident from the gradual increase in time with respect to the number of
elements.
Q2.]
a.] Implement a parallelized merge sort algorithm to sort a
given set of elements and determine the time required to sort the
elements.

ANS.

Algorithm: To sort A[p .. r]:

1. Divide Step
If a given array A has zero or one element, simply return; it is already sorted.
Otherwise, split A[p .. r] into two subarrays A[p .. q] and A[q + 1 .. r], each
containing about half of the elements of A[p .. r]. That is, q is the halfway point
of A[p .. r].

2. Conquer Step
Conquer by recursively sorting the two subarrays A[p .. q] and A[q + 1 .. r].

3. Combine Step
Combine the elements back in A[p .. r] by merging the two sorted
subarrays A[p .. q] and A[q + 1 .. r] into a sorted sequence. To accomplish this
step, we will define a procedure MERGE (A, p, q, r).

Note that the recursion bottoms out when the subarray has just one element, so
that it is trivially sorted.

#CODE:

import time
import random
import matplotlib.pyplot as plt
from concurrent.futures import ThreadPoolExecutor

def merge(left, right):


result = []
i=j=0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result.extend(left[i:])
result.extend(right[j:])
return result

def parallel_merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
with ThreadPoolExecutor(max_workers=2) as executor:
left_future = executor.submit(parallel_merge_sort, arr[:mid])
right_future = executor.submit(parallel_merge_sort, arr[mid:])
left = left_future.result()
right = right_future.result()
return merge(left, right)

b.] Repeat the experiment for different values of n, the


number of elements in the list to be sorted and plot a graph of the
time taken versus n. The elements can be read from a file or can be
generated using the random number generator.

ANS.

def measure_time(n):
arr = [random.randint(0, 10000) for _ in range(n)]
start_time = time.time()
parallel_merge_sort(arr)
end_time = time.time()
return end_time - start_time

# Experiment and plot

sizes = [100, 500, 1000, 5000, 10000]


times = []
for size in sizes:
elapsed_time = measure_time(size)
times.append(elapsed_time)
print(f"Time to sort {size} elements: {elapsed_time:.4f} seconds")

plt.plot(sizes, times, marker='o')


plt.xlabel('Number of Elements (n)')
plt.ylabel('Time Taken (seconds)')
plt.title('Time Complexity of Parallel Merge Sort')
plt.grid(True)
plt.show()

Soln.

Time to sort 100 elements: 0.0359 seconds


Time to sort 500 elements: 0.2621 seconds
Time to sort 1000 elements: 0.4102 seconds
Time to sort 5000 elements: 3.2667 seconds
Time to sort 10000 elements: 10.7879 seconds
Q3.]
a.] Obtain the Topological ordering of vertices in a given
digraph

ANS.
Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of
vertices such that for every directed edge uv, vertex u comes before v in the
ordering. Topological Sorting for a graph is not possible if the graph is not a DAG.
Input parameters: int a[MAX][MAX] - adjacency matrix of the input graph int n - no
of vertices in the graph

CODE :
#include <stdio.h>

const int MAX = 10;


void fnTopological(int a[MAX][MAX], int n);
int main(void){
int a[MAX][MAX],n;
int i,j;

printf("Topological Sorting Algorithm -\n");


printf("\nEnter the number of vertices : ");
scanf("%d",&n);

printf("Enter the adjacency matrix -\n");


for (i=0; i<n; i++)
for (j=0; j<n; j++)
scanf("%d",&a[i][j]);
fnTopological(a,n);
printf("\n");
return 0;
}

void fnTopological(int a[MAX][MAX], int n){


int in[MAX], out[MAX], stack[MAX], top=-1;
int i,j,k=0;

for (i=0;i<n;i++){
in[i] = 0;
for (j=0; j<n; j++)
if (a[j][i] == 1)
in[i]++;
}

while(1){
for (i=0;i<n;i++){
if (in[i] == 0){
stack[++top] = i;
in[i] = -1;
}
}

if (top == -1)
break;

out[k] = stack[top--];

for (i=0;i<n;i++){
if (a[out[k]][i] == 1)
in[i]--;
}
k++;
}

printf("Topological Sorting (JOB SEQUENCE) is:- \n");


for (i=0;i<k;i++)
printf("%d ",out[i] + 1);
}

OUTPUT

Input Graph : 5 vertices 0 0 1 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0


Topological Sorting (JOB SEQUENCE) is:- 2 1 3 4 5
b]. Compute the transitive closure of a given directed graph
using Warshall's algorithm.

Ans.

class Graph:

def __init__(self, vertices):


self.V = vertices

# A utility function to print the solution


def printSolution(self, reach):
print ("Following matrix transitive closure of the given graph ")
for i in range(self.V):
for j in range(self.V):
if (i == j):
print ("%7d\t" % (1),end=" ")
else:
print ("%7d\t" %(reach[i][j]),end=" ")
print()

# Prints transitive closure of graph[][] using Floyd Warshall algorithm


def transitiveClosure(self,graph):
reach =[i[:] for i in graph]
for k in range(self.V):

# Pick all vertices as source one by one


for i in range(self.V):

# Pick all vertices as destination for the


# above picked source
for j in range(self.V):

# If vertex k is on a path from i to j,


# then make sure that the value of reach[i][j] is 1
reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j])
self.printSolution(reach)
g= Graph(4)
graph = [[1, 1, 0, 1],
[0, 1, 1, 0],
[0, 0, 1, 1],
[0, 0, 0, 1]]

#Print the solution


g.transitiveClosure(graph)

OUTPUT

Following matrix is transitive closure of the given graph


1111
0111
0011
0001
Q4. Implement 0/1 Knapsack problem using Dynamic
Programming.

Ans.

Problem Definition
 Items: n items each with a weight wi and vi .
 Knapsack Capacity: W.
 Objective: Maximize the total value of items in the knapsack without
exceeding its weight capacity.

CODE
def knapsack(values, weights, capacity):
n = len(values)

# Initialize DP table with zeros


dp = [[0] * (capacity + 1) for _ in range(n + 1)]

# Fill the DP table


for i in range(1, n + 1):
for w in range(1, capacity + 1):
if weights[i-1] <= w: # Include the item
dp[i][w] = max(dp[i-1][w], values[i-1] + dp[i-1][w - weights[i-1]])
else: # Do not include the item
dp[i][w] = dp[i-1][w]

# The maximum value that can be obtained with given capacity


return dp[n][capacity]
Q5. From a given vertex in a weighted connected graph, find
shortest paths to other vertices using Dijkstra's algorithm.

Ans.

1. We will use the above graph as the


input, with node A as the source.
2. First, we will mark all the nodes as
unvisited.
3. We will set the path to 0 at
node A and INFINITY for all the other
nodes.
4. We will now mark source node A as
visited and access its neighboring nodes.
Note: We have only accessed the neighboring nodes, not visited them.
5. We will now update the path to node B by 4 with the help of relaxation
because the path to node A is 0 and the path from node A to B is 4, and
the minimum((0 + 4), INFINITY) is 4.
6. We will also update the path to node C by 5 with the help of relaxation
because the path to node A is 0 and the path from node A to C is 5, and
the minimum((0 + 5), INFINITY) is 5. Both the neighbors of node A are now
relaxed; therefore, we can move ahead.

7. We will now select the next unvisited node with the least path and visit it.
Hence, we will visit node B and perform relaxation on its unvisited
neighbors. After performing relaxation, the path to node C will remain 5,
whereas the path to node E will become 11, and the path to node D will
become 13.

8. We will now visit node E and perform relaxation on its neighboring nodes B,
D, and F. Since only node F is unvisited, it will be relaxed. Thus, the path to
node B will remain as it is, i.e., 4, the path to node D will also remain 13,
and the path to node F will become 14 (8 + 6).

9. Now we will visit node D, and only node F will be relaxed. However, the
path to node F will remain unchanged, i.e., 14.

10. Since only node F is remaining, we will visit it but not perform any
relaxation as all its neighboring nodes are already visited.
Once all the nodes of the graphs are visited, the program will end.

OUTPUT

A=0
B = 4 (A -> B)
C = 5 (A -> C)
D = 4 + 9 = 13 (A -> B -> D)
E = 5 + 3 = 8 (A -> C -> E)
F = 5 + 3 + 6 = 14 (A -> C -> E -> F)
Q6. Find Minimum Cost Spanning Tree of a given undirected graph
using Kruskal's algorithm.

Ans.
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.

EX:
Find the MST of the following:

Soln.
Q7.
a.] Print all the nodes reachable from a given starting node in a
digraph using BFS method.

Ans.

1. Initialization: Enqueue the starting node into a queue and mark it as visited.
2. Exploration: While the queue is not empty:
 Dequeue a node from the queue and visit it (e.g., print its value).
 For each unvisited neighbor of the dequeued node:
o Enqueue the neighbor into the queue.
o Mark the neighbor as visited.
3. Termination: Repeat step 2 until the queue is empty.

This algorithm ensures that all nodes in the graph are visited in a breadth-first
manner, starting from the starting node.
b.] Check whether a given graph is connected or not using DFS
method.

Ans.

Algorithm

1. Take two bool arrays vis1 and vis2 of size N (number of nodes of a graph)
and keep false in all indexes.
2. Start at a random vertex v of the graph G, and run a DFS(G, v).
3. Make all visited vertices v as vis1[v] = true.
4. Now reverse the direction of all the edges.
5. Start DFS at the vertex which was chosen at step 2.
6. Make all visited vertices v as vis2[v] = true.
7. If any vertex v has vis1[v] = false and vis2[v] = false then the graph is not
connected.

CORRECT INCORRECT
Q8. Find Minimum Cost Spanning Tree of a given undirected graph
using Prim’s algorithm.

Ans.

We start from one vertex and keep adding edges with the lowest weight until we
reach our goal.
The steps for implementing Prim's algorithm are as follows:
1. Initialize the minimum spanning tree with a vertex chosen at random.
2. Find all the edges that connect the tree to new vertices, find the minimum
and add it to the tree
3. Keep repeating step 2 until we get a minimum spanning tree

EX:
Find the MST of the following:

Soln.

You might also like