0% found this document useful (0 votes)
18 views

Cs3401-Algorithm Lab Manual

The document outlines various programming exercises focused on search algorithms (Linear and Binary), pattern matching, sorting methods (Insertion and Heap), and graph traversal techniques (Breadth First Search and Depth First Search). Each exercise includes an aim, algorithm, program code, and results, demonstrating the implementation and performance of these algorithms. The document also discusses Dijkstra's algorithm for finding the shortest paths in a graph.

Uploaded by

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

Cs3401-Algorithm Lab Manual

The document outlines various programming exercises focused on search algorithms (Linear and Binary), pattern matching, sorting methods (Insertion and Heap), and graph traversal techniques (Breadth First Search and Depth First Search). Each exercise includes an aim, algorithm, program code, and results, demonstrating the implementation and performance of these algorithms. The document also discusses Dijkstra's algorithm for finding the shortest paths in a graph.

Uploaded by

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

Ex.

No: 1 Linear Search

Aim

To implement Linear Search and determine the time required to search for an
element.
Repeat the experiment for different values of n, the number of elements in the list to
be searched and plot a graph of the time taken versus n.

Algorithm

1. Create the linear search () function.


2. Declare the list1, n, and key value to be found as three parameters.
3. Initialize the for a loop.
4. Compare the value of the key with each element as you iterate.
5. Return index if the element is present.
6. else return element is absent.
Program

import matplotlib.pyplot
as plt import numpy as
np
import timeit import
math import random
def
linear_Search(list1,n,ke
y): for i in range(0,n):
if(list1[i]==key):
return
i return
-1
list1=[1,3,5,4,7,9]
key=7
n=len(list
1)
res=linear_Search(list1,n,
key) if(res==-1):
print("element not
found") else:
print("element found at
index:",res) def contains(lst,x):
for y in
lst: if
x==y:
return
True return
False
ns=np.linspace(10,10_000,100,dtype=int)
ts=[timeit.timeit('contains(lst,0)',
setup='lst=list(range({}));random.shuffle(lst)'.f
ormat(n), globals=globals(),
number=10
0) for n in
ns]
plt.plot(ns,ts,'or')
degree=4
coeffs=np.polyfit(ns,ts,degr
ee) p=np.poly1d(coeffs)
plt.plot(ns,[p(n) for n in
ns],'-r')
ts=[timeit.timeit('contains(l
st,-1)',
setup='lst=list(range({}));random.shuffle(lst)'.format(n),
globals=globals(), number=100)
for n in
ns]
plt.plot(ns,ts,'ob')
degree=4
coeffs=np.polyfit(ns,ts,de
gree) p=np.poly1d(coeffs)
plt.plot(ns,[p(n) for n in
ns],'-b')

OUTPUT
element found at index: 4

Result

Thus the program has been created, executed and the output is verified.
Ex. No: 2 Binary Search

Aim

To implement recursive Binary Search and determine the time required to


search an element. Repeat the experiment for different values of n, the number of
elements in the list to be searched and plot a graph of the time taken versus n.

Algorithm

1. Create the binary search () function.


2. Declare the num and target as two parameters.
3. Initialize start=0 and end=length minus 1.
4. Check if target is greater than the mid element then end=mid-1
5. Else if target is less than the mid element then start=mid +1
6. Else return mid element
Program

import matplotlib.pyplot
as plt import numpy as
np
import timeit import
math import random
def
search(nums,target):
start=0
end=len(nums)-1
while start<=end:
mid=start+(end-
start)//2 if
nums[mid]>target:
end=mid-1
elif
nums[mid]<targ
et: satrt=mid+1
else:
return
mid
return -1
if name ==' main ':
nums=[2,12,15,17,27,2
9,45]
target=17
print(search(nums,target)) def
contains(lst,x):
lo=0
hi=len(lst)-1
while lo <= hi:
mid=(lo+hi)//
2 if
x<lst[mid]:
hi=mid-1
elif x>lst[mid]:
lo=mid
+1 else:
return
True else:
return False
ns=np.linspace(10,10_000,100,dtype=int)
ts=[timeit.timeit('contains(lst,0)',
setup='lst=list(range({}));random.shuffle(lst)'.format(n),
globals=globals(), number=100)
for n in
ns]
plt.plot(ns,ts,'or')
degree=4
coeffs=np.polyfit(ns,ts,de
gree) p=np.poly1d(coeffs)
plt.plot(ns,[p(n) for n in
ns],'-b')
OUTPUT
3

Result:

Thus the program has been created, executed and the output is verified
Ex. No: 3 Pattern Matching

Aim
To write a function search (char pat [ ], char txt [ ]) that prints all occurrences of pat [ ]
in txt [ ].

Algorithm

1. Create the search function and declare the two parameters pat and txt.
2. Initialize the for loop i=0 to i≤N-M+1, and the inner loop will range from j=0 to
j<m, where ‘M’ is the length of the input pattern and N is the length of the text
string.
3. If a match is not found, we will break from the loop(using the 'break' keyword),
and the j pointer of the inner loop will move one index more and start the
search algorithm in the next window
4. If a match is found, we will match the entire pattern with the current window of
the text string. And if found the pattern string is found.print the result
Program

# Python3 program for Naive


Pattern # Searching algorithm
def search(pat, txt):
M=
len(pat) N
= len(txt)
# A loop to slide pat[] one by
one */ for i in range(N - M + 1):
j=0
# For current index i,
check # for pattern
match */ while(j < M):
if (txt[i + j] != pat[j]):
break
j += 1
if (j == M):
print("Pattern found at index ", i)
# Driver's
Code
if name == ' main ':
txt =
"AABAACAADAABAAABAA"
pat = "AABA"

# Function
call
search(pat,
txt)
Output

Pattern found at index 0


Pattern found at index 9
Pattern found at index 13

Result:
Thus the program has been created, executed and the output is verified
Ex. No: 4 Sorting the elements using Insertion and

Heap

Aim
To sort a given set of elements using the Insertion sort and Heap sort methods
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.

Algorithm
1. Create the insertion sort function.
2. Initialize the for loop i=1 to array length.
3. If it is the first element, then place it in the sorted sub-array.
4. Pick the next element.
5. Compare the picked element with all the elements in sorted sub-array.
6. Shift all the elements in the sorted sub-array that are greater than the picked
element to be sorted.
7. Insert the element at the desired place.
8. Repeat the above steps until the array is completely sorted.
Program

import matplotlib.pyplot
as plt import numpy as
np
import timeit
import math
import random def
insertionSort(arr):
for i in
range(1,len(arr)):
key=arr[i]
j=i-1
while j>=0 and
key<arr[j]:
arr[j+1]=arr[j]
j-=1
arr[j+1]=key
arr=[12,11,13,5,6]
insertionSort(arr)
for i in
range(len(arr)):
print("%d"%arr[i
])

def insertion_sort(lst):
for i in
range(1,len(lst)): for
j in range(i,0,-1):
if lst[j-1]>lst[j]:
lst[j-
1],lst[j]=lst[j],lst[j-1]
else:
break
ns=np.linspace(100,2000,15,dtype=int)
ts=[timeit.timeit('insertion_sort(lst)',
setup='lst=list(range({}));random.shuffle(lst)'.f
ormat(n), globals=globals(),
number=
1) for n
in ns]
plt.plot(ns,ts,'or')
degree=4
coeffs=np.polyfit(ns,ts,de
gree) p=np.poly1d(coeffs)
plt.plot(ns,[p(n) for n in
ns],'-r')
OUTPUT
5
6
11
12
13
Heap Sort

# Python program for implementation of heap Sort

# To heapify subtree rooted at


index i. # n is size of heap
def heapify(arr, N, i):
largest = i # Initialize largest
as root l = 2 * i + 1 # left =
2*i + 1
r = 2 * i + 2 # right = 2*i + 2
# See if left child of root exists
and is # greater than root
if l < N and arr[largest]
<arr[l]: largest = l
# See if right child of root exists
and is # greater than root
if r < N and arr[largest]
<arr[r]: largest = r
# Change root, if
needed if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
# swap # Heapify the root.
heapify(arr, N, largest)
# The main function to sort an array of
given size def heapSort(arr):
N = len(arr)
# Build a maxheap.
for i in range(N//2 - 1, -1,
-1): heapify(arr, N,
i)

# One by one extract


elements for i in range(N-1,
0, -1):
arr[i], arr[0] = arr[0], arr[i] # swap
heapify(arr, i, 0)
# Driver's code
if name == ' main
': arr = [12, 11, 13,
5, 6, 7]
# Function
call
heapSort(arr
)N=
len(arr)
print("Sorted array
is") for i in
range(N):
print("%d" % arr[i], end=" ")
Outpu
t
Sorted array
is 5 6 7 11
12 13

Result:
Thus the program has been created, executed and the output is verified
Ex. No: 5 Graph Traversal using Breadth First

Search Aim:

To develop a program to implement graph traversal using Breadth First Search.

Algorithm

1. Start node to the Queue.


2. For every node, set that they don't have a defined parent node.
3. Until the Queue is empty:
 Extract the node from the beginning of the Queue.
 Perform output processing.
 For every neighbor of the current node that doesn't have a defined
parent (is not visited), add it to the Queue, and set the current node
as their parent.
Program

from collections import

defaultdict class Graph:

# Constructor

def init (self):

# default dictionary to store graph

self.graph = defaultdict(list)

# function to add an edge to

graph def addEdge(self,u,v):

self.graph[u].append(v)

# Function to print a BFS of

graph def BFS(self, s):

# Mark all the vertices as not visited visited =

[False] * (len(self.graph))

# Create a queue for BFS queue = []

# Mark the source node as # visited

and enqueue it queue.append(s)

visited[s] = True while

queue:

g = Graph()
g.addEdge(0, 1)

g.addEdge(0, 2)

g.addEdge(1, 2)

g.addEdge(2, 0)

g.addEdge(2, 3)

g.addEdge(3, 3)

print ("Following is Breadth First Traversal" (starting from


vertex 2)") g.BFS(2)

Output

Following is Breadth First Traversal (starting from


vertex 2) 2 0 3 1

Result:

Thus the program has been created, executed and the output is verified.
Ex. No: 6 Graph Traversal using Depth First

Search

Aim

To develop a program to implement graph traversal using Depth First Search

Algorithm

1. Create a recursive function that takes the index of the node and a visited array.

2. Mark the current node as visited and print the node.

3. Traverse all the adjacent and unmarked nodes and call the recursive
function with the index of the adjacent node.
Program

from collections import


defaultdict class Graph:
def init (self):
self.graph=defaultdict
(list)
def addEdge(self,u,v):
self.graph[u].appen
d(v)
def DFSUtil(self,v,visited):
visited[v]=True
print (v) for i in
self.graph[v]: if
visited[i]==False:
self.DFSUtil(i,visited)
def DFS(self):
V=len(self.graph) visited=[False]*(V) for i
in range(V):
if visited[i]==False:
self.DFSUtil(i,visited)
g=Graph()
g.addEdge(0,1)
g.addEdge(0,2)g.ad
dEdge(1,2)
g.addEdge(2,0)
g.addEdge(2,3)
g.addEdge(3,3)
print("Following is Depth First
Traversal") g.DFS()
Output:

Following is Depth First

Traversal 0 1 2 3

Result:

Thus the program has been created, executed and the output is verified.
Ex. No: 7 Dijkstra’s Algorithm

Aim

To develop a program to find the shortest paths to other vertices using Dijkstra’s
algorithm.

Algorithm

1. Create a set sptSet (shortest path tree set) that keeps track of vertices included
in shortest path tree, i.e., whose minimum distance from source is calculated
and finalized. Initially, this set is empty.
2. Assign a distance value to all vertices in the input graph. Initialize all
distance values as INFINITE. Assign distance value as 0 for the source
vertex so that it is picked first.
3. While sptSet doesn’t include all vertices:
 Pick a vertex u which is not there in sptSet and has minimum
distance value.
 Include u to sptSet.
Update distance value of all adjacent vertices of u. To update the distance values,
iterate through all adjacent vertices. For every adjacent vertex v, if the sum of a
distance value of u (from source) and weight of edge u-v, is less than the distance
value of v, then update the distance value of v.
Program

Class Graph ():

class Graph():
def init (self, vertices):
self.V = vertices
self.graph = [[0 for column in
range(vertices)] for row in
range(vertices)]
def printSolution(self, dist):
print("Vertex \t Distance from
Source") for node in
range(self.V):
print(node, "\t\t", dist[node])
def minDistance(self, dist,
sptSet): min = 1e7
for v in range(self.V):
if dist[v] < min and sptSet[v] ==
False: min = dist[v]
min_index =
v return
min_index def
dijkstra(self, src):
dist = [1e7] *
self.V dist[src] =
0
sptSet = [False] * self.V
for cout in
range(self.V):
u = self.minDistance(dist,
sptSet) sptSet[u] = True
for v in range(self.V):
if (self.graph[u][v] > 0
and sptSet[v] ==
False and
dist[v] > dist[u] +
self.graph[u][v]): dist[v] =
dist[u] + self.graph[u][v]
self.printSolution(d
ist) g = Graph(9)
g.graph = [[0, 4, 0, 0, 0, 0, 0, 8,
0],
[4, 0, 8, 0, 0, 0, 0, 11, 0],
[0, 8, 0, 7, 0, 4, 0, 0, 2],
[0, 0, 7, 0, 9, 14, 0, 0, 0],
[0, 0, 0, 9, 0, 10, 0, 0, 0],
[0, 0, 4, 14, 10, 0, 2, 0, 0],
[0, 0, 0, 0, 0, 2, 0, 1, 6],
[8, 11, 0, 0, 0, 0, 1, 0, 7],
[0, 0, 2, 0, 0, 0, 6, 7, 0] ]
g.dijkstra(0)
Output:

Vertex Distance from


Source
0 0
1 4
2 12
3 19
4 21
5 11
6 9
7 8
8 14

Result:

Thus the program has been created, executed and the output is verified.
Ex. No: 8 Prim’s

Algorithm

Aim

To find the minimum cost spanning tree of a given undirected graph using Prim’s
algorithm.

Algorithm

1. Create a set mstSet that keeps track of vertices already included in MST.
2. Assign a key value to all vertices in the input graph. Initialize all key values
as INFINITE. Assign the key value as 0 for the first vertex so that it is
picked first.
3. While mstSet doesn’t include all vertices
 Pick a vertex u that is not there in mstSet and has a minimum key value.
 Include u in the mstSet.
 Update the key value of all adjacent vertices of u. To update the key
values, iterate through all adjacent vertices.
 For every adjacent vertex v, if the weight of edge u-v is less than
the previous key value of v, update the key value as the weight of
u-v.
Program
class Graph:
def init (self, num_of_nodes):
self.m_num_of_nodes =
num_of_nodes
self.m_graph = [[0 for column in
range(num_of_nodes)] for row in
range(num_of_nodes)]
def add_edge(self, node1, node2,
weight): self.m_graph[node1]
[node2] = weight
self.m_graph[node2][node1] =
weight
def prims_mst(self):
postitive_inf = float('inf')
selected_nodes = [False for node in
range(self.m_num_of_nodes)] result = [[0 for column in
range(self.m_num_of_nodes)]
for row in
range(self.m_num_of_nodes)] indx
=0
for i in
range(self.m_num_of_nodes):
print(self.m_graph[i])
print(selected_nodes
while(False in
selected_nodes):
minimum = postitive_inf
start = 0
end = 0
for i in range(self.m_num_of_nodes):
if selected_nodes[i]:
for j in range(self.m_num_of_nodes):
if(not selected_nodes[j] and
self.m_graph[i][j]>0): if self.m_graph[i][j]
< minimum:
minimum =
self.m_graph[i][j] start,
end = i, j
selected_nodes[end] =
True result[start][end] =
minimum if minimum
== postitive_inf:
result[start][end] = 0
print("(%d.) %d - %d: %d" % (indx, start, end,
result[start][end])) indx += 1
result[end][start] =
result[start][end] for i in
range(len(result)):
for j in range(0+i, len(result)):
if result[i][j] != 0:
print("%d - %d: %d" % (i, j,
result[i][j])) example_graph = Graph(9)
example_graph.add_edge(0, 1, 4)
example_graph.add_edge(0, 2, 7)
example_graph.add_edge(1, 2, 11)
example_graph.add_edge(1, 3, 9)
example_graph.add_edge(1, 5, 20)
example_graph.add_edge(2, 5, 1)
example_graph.add_edge(3, 6, 6)
example_graph.add_edge(3, 4, 2)
example_graph.add_edge(4, 6, 10)
example_graph.add_edge(4, 8, 15)
example_graph.add_edge(4, 7, 5)
example_graph.add_edge(4, 5, 1)
example_graph.add_edge(5, 7, 3)
example_graph.add_edge(6, 8, 5)
example_graph.add_edge(7, 8,
12)
example_graph.prims_mst()

OUTPUT

[0, 4, 7, 0, 0, 0, 0, 0, 0]
[4, 0, 11, 9, 0, 20, 0, 0, 0]
[7, 11, 0, 0, 0, 1, 0, 0, 0]
[0, 9, 0, 0, 2, 0, 6, 0, 0]
[0, 0, 0, 2, 0, 1, 10, 5, 15]
[0, 20, 1, 0, 1, 0, 0, 3, 0]
[0, 0, 0, 6, 10, 0, 0, 0, 5]
[0, 0, 0, 0, 5, 3, 0, 0, 12]
[0, 0, 0, 0, 15, 0, 5, 12, 0]

[False, False, False, False, False, False, False, False, False]

(0.) 0 - 0: 0
(1.) 0 - 1: 4
(2.) 0 - 2: 7
(3.) 2 - 5: 1
(4.) 5 - 4: 1
(5.) 4 - 3: 2
(6.) 5 - 7: 3
(7.) 3 - 6: 6
(8.) 6 - 8: 5

0 - 1: 4
0 - 2: 7
2 - 5: 1
3 - 4: 2
3 - 6: 6
4 - 5: 1
5 - 7: 3
6 - 8: 5

Result:

Thus the program has been created, executed and the output is verified.

Ex. No: 9 Floyd’s

Algorithm

Aim
To implement Floyd’s algorithm for the All-Pairs- Shortest-Paths problem.

Algorithm

1. Initialize the solution matrix same as the input graph matrix as a first step.
2. Considering all vertices as an intermediate vertex. Pick all vertices and updates all
shortest paths which include the picked vertex as an intermediate vertex in the
shortest path.
3. When we pick vertex number k as an intermediate vertex, we already have
considered vertices {0, 1, 2... k-1} as intermediate vertices.
4. For every pair (i, j) of the source and destination vertices respectively, there are
two possible cases.
 K is not an intermediate vertex in shortest path from i to j. We keep
the value of dist[i][j] as it is.
 K is an intermediate vertex in shortest path from i to j. We update the
value of dist[i][j] as dist[i][k] + dist[k][j] if dist[i][j] > dist[i][k] + dist[k
Progra
m

nV = 4
INF = 999
def floyd_warshall(G):
distance = list(map(lambda i: list(map(lambda j: j,
i)), G)) for k in range(nV):
for i in range(nV):
for j in range(nV):
distance[i][j] = min(distance[i][j], distance[i][k] + distance[k]
[j]) print_solution(distance)
def
print_solution(distance):
for i in range(nV):
for j in range(nV):
if(distance[i][j] ==
INF):
print("INF", end=" ") else:
print(distance[i][j],
end=" ") print(" ")
G = [[0, 3, INF, 5],
[2, 0, INF, 4],
[INF, 1, 0, INF],
[INF, INF, 2, 0]]
floyd_warshall(G)
OUTPUT
03 5
7
20 4
6
31 5
0
53 0
2

Result:

Thus the program has been created, executed and the output is verified.
Ex. No: 10 Warshall’s

Algorithm

Aim

To compute the transitive closure of a given directed graph using Warshall's


algorithm.

Algorithm

1. Create a Boolean reach-ability matrix reach[V][V] .


2. The value reach[i][j] will be 1 if j is reachable from i, otherwise 0.
3. Instead of using arithmetic operations, use logical operations.
4. For arithmetic operation ‘+’, logical and ‘&&’ is used, and for a ‘-‘, logical or ‘||’
is used.
Program

from collections import


defaultdict class Graph:
def init (self, vertices):
self.V = vertices
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()
def transitiveClosure(self,graph):
reach =[i[:] for i in
graph] for k in
range(self.V):
for i in range(self.V):
for j in range(self.V):
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]]
g.transitiveClosure(graph)
OUTPUT

Following matrix transitive closure of the given graph


1 1 1 1
0 1 1 1
0 0 1 1
0 0 0 1

Result:

Thus the program has been created, executed and the output is verified.
Ex. No: 11 State Space Search

Aim:
To implement N Queens problem using Backtracking.

Algorithm
1. Initialize an empty chessboard of size NxN.
2. Start with the leftmost column and place a queen in the first row of that column.
3. Move to the next column and place a queen in the first row of that column.
4. Repeat step 3 until either all N queens have been placed or it is impossible to
place a queen in the current column without violating the rules of the problem.
5. If all N queens have been placed, print the solution.
6. If it is not possible to place a queen in the current column without violating
the rules of the problem, backtrack to the previous column.
7. Remove the queen from the previous column and move it down one row.
8. Repeat steps 4-7.
Program

global N N = 4
def PrintSolution(board):
for i in range(N):
for j in range(N):
print(board[i]
[j],end='') print()
def isSafe(board,row,col):
for i in range(col):
if board[row][i] == 1:
return False
for i,j in zip(range(row,-1,-1),range(col,-
1,-1)): if board[i][j] == 1:
return False
for i,j in zip(range(row,-1,-1),range(col,-
1,-1)): if board[i][j] == 1:
return
False return
True
def SolveNQUtil(board,col):
if col >= N:
return True
for i in range(N):
if isSafe(board,i,col):
board[i][col] = 1
if SolveNQUtil(board,col+1) ==
True: return True
board[i][col]
= 0 return
False
def SolveNQ():
board= [[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0] ]
ifSolveNQUtil(board,0)==False
: print("SOlution does not
exist")
return False
PrintSolution(boa
rd) return True
SolveNQ()
OUTPUT
0010
1000
0001
0100
True
Result:

Thus the program has been created, executed and the output is verified

Ex. No: 12 Travelling Salesman

Problem

Aim
To find the optimal solution for the Traveling Salesperson problem and then solve the
same
problem instance using any approximation algorithm and determine the error in the
approximation.

Algorithm

1. Construct MST.
2. Determine an arbitrary vertex as the starting vertex of the MST.
3. Follow steps 3 to 5 till there are vertices that are not included in the MST
4. Find edges connecting any tree vertex with the fringe vertices.
5. Find the minimum among these edges.
6. Add the chosen edge to the MST if it does not form any cycle.
7. Return the MST and exit.
Program

from sys import maxsize


from itertools import
permutations V = 4
def
TravellingSalesmanProblem(graph,
s): vertex = []
for i in range(V):
if i != s:
vertex.append
(i) min_path =
maxsize
next_permutation=permutations(ve
rtex) for i in next_permutation:
current_pathweight = 0
k = s for j in i:
current_pathweight += graph[k]
[j] k = j current_pathweight +=
graph[k][s]
min_path = min(min_path,
current_pathweight) return min_path
if name == " main ":
graph = [[0,10,15,20],
[10,0,35,25],
[15,35,0,30], [20,25,30,0]]
s = 0 print(TravellingSalesmanProblem(graph, s))
OUTPUT
80

Result:

Thus the program has been created, executed and the output is verified.

You might also like