Cs3401 - Algorithms Lab Manual
Cs3401 - Algorithms Lab Manual
LAB MANUAL
P repared by
Ms. SARANYA K
AP(Sr.G)/CSE
1|Page
CS3401 ALGORITHMS LABORATORY LTPC
0042
COURSE OBJECTIVES:
To understand and apply the algorithm analysis techniques on searching and sortingalgorithms.
To critically analyze the efficiency of graph algorithms
To understand different algorithm design techniques
To solve programming problems using state space tree
To understand the concepts behind NP Completeness, Approximation algorithms
andrandomized algorithms.
LIST OF EXPERIMENTS:
COURSE OUTCOMES:
TOTAL: 75 PERIODS
5|Page
CONTENTS
ALGORITHM:
1. Declare an array.
2. The linear_search function takes an array arr and an element x as input, and searches for the
element in the array using linear search.
3. If the element is found, it returns the index of the element in the array. Otherwise, it returns -1.
4. The program defines a list n_values containing different values of n to test the linear
search algorithm on.
5. It then loops through this list, generates a random list of n elements, and searches for a
random element in the list.
6. It measures the time taken to perform the search using the time module, and appends the
time taken to a list time_values.
7. Finally, the program uses matplotlib library to plot a graph of the time taken versus n.
PROGRAM:
import time
import [Link] as plt import random
for n in n_values:
arr = [[Link](0, n) for _ in range(n)]
x = [Link](0, n)
start_time = [Link]()
linear_search(arr, x)
end_time = [Link]()
time_values.append(end_time - start_time)
[Link](n_values, time_values)
[Link]('Linear Search')
[Link]('Number of Elements')
[Link]('Time Taken
(seconds)') [Link]()
7|Page
lOM oARcPSD|3 1 3 1 7 4 54
OUTPUT:
Output 1:
Output 2:
Result:
Thus the python program for implementation of linear search program was executed and verified
successfully.
8|Page
lOM oARcPSD|3 1 3 1 7 4 54
ALGORITHM:
1. Declare the array.
2. ‘binary_search_recursive’ is a recursive function that takes an array ‘arr’, the lower and
upper bounds of the subarray being searched ‘low ‘and ‘high', and the element being searched for
‘x’.
3. It returns the index of the element if it is found, or -1 if it is not found.
4. The function ‘test_binary_search_recursive’ generates arrays of different sizes and runs a
binary search for a random element in each array.
5. It records the time taken to run the search and plots it on a graph.
6. The graph shows the time taken to search for an element versus the size of the array
being searched.
7. As the size of the array increases, the time taken to search for an element increases as well, but
the increase is logarithmic since binary search has a time complexity of O (log n).
PROGRAM:
import random
import time
import [Link] as plt
def test_binary_search_recursive():
for n in [10, 100, 1000, 10000, 100000]:
arr = [[Link](1, n) for i in range(n)]
[Link]()
start_time = [Link]()
x = [Link](1, n)
result = binary_search_recursive(arr, 0, n-1, x)
end_time = [Link]()
9|Page
lOM oARcPSD|3 1 3 1 7 4 54
if result == -1:
print(f"Element {x} not found in the array")
else:
print(f"Element {x} found at index {result}")
test_binary_search_recursive()
10 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
OUTPUT:
Element 4 not found in the array
Time taken to search in array of size 10: 7.3909759521484375e-06
==================================================
Element 31 found at index 36
Time taken to search in array of size 100: 7.867813110351562e-06
==================================================
Element 414 found at index 393
Time taken to search in array of size 1000: 1.9311904907226562e-05
==================================================
Element 4378 not found in the array
Time taken to search in array of size 10000: 4.673004150390625e-05
==================================================
Element 52551 found at index 52435
Time taken to search in array of size 100000: 4.482269287109375e-05
=======================================
Result:
Thus the python program for implementation of recursive binary search was executed and
verified successfully.
11 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
AIM:
To implement all occurrences of pat [ ] in txt [ ]. You may assume that n > m. Given a text
txt [0...n-1] and a pattern pat [0...m-1], write a function search (char pat [ ], char txt [ ]).
ALGORITHM:
1. One way to implement the search function is to use the brute-force approach, which
involves comparing each possible substring of the text with the pattern.
2. The algorithm iterates through the text from the first character to the (n-m)th character and checks
whether the pattern matches the substring of the text starting at that position.
3. If a match is found, the function prints the index of the match.
PROGRAM:
return result
txt = "AABAACAADAABAABA"
pat = "AABA"
result = search(pat, txt)
print("Pattern found at indices:", result)
OUTPUT:
Result:
Thus the python program implementation of pattern matching was executed and verified.
12 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
SORT 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. The insertionSort function takes a list of elements and sorts them using the Insertion sort algorithm.
2. The generateList function generates a list of n random numbers between 1 and 1000.
3. The measureTime function generates a list of n random numbers, sorts it using the insertionSort
func tion, and measures the time required to sort the list.
4. The plotGraph nction generates a list of n values and calls the measureTime function for each
n value. It then plots a graph of the time required to sort the list versus the value of n.
1. The heapify function takes an array arr, the size of the heap n, and the root index i of the subtree
to heapify. It compares the root node with its left and right children and swaps the root with the
larger child if necessary. The function then recursively calls itself on the subtree with the new root
index.
2. The heapSort function takes an array arr and sorts it using the Heap sort algorithm. It first builds
a max heap by heapifying all subtrees bottom-up. It then repeatedly extracts the maximum element
from the heap and places it at the end of the array.
3. The generateList function generates a list of n random numbers between 1 and 1000.
4. The measureTime function generates a list of n random numbers, sorts it using the
heapSort function, and measures the time required to sort the list.
5. The plotGraph function generates a list of n values and calls the measureTime function for each
n value.
6. It then plots a graph of the time required to sort the list versus the value of n.
PROGRAM:
INSERTION SORT
import [Link] as
plt import random
import time
def insertionSort(arr): n = len(arr)
for i in range(1, n): key = arr[i]
j=i-1
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j]
14 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
j-=1
arr[j + 1] = key
OUTPUT:
15 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
PROGRAM:
HEAPSORT
import [Link] as
plt import random
import time
startTime = [Link]()
heapSort(arr)
endTime = [Link]()
return endTime - startTime
OUTPUT:
RESULT:
Thus the python program for implementation of insertion sort and heap sort was executed
and verified successfully.
17 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
ALGORITHM:
1. Start by putting any one of the graph's vertices at the back of a queue.
2. Take the front item of the queue and add it to the visited list.
3. Create a list of that vertex's adjacent nodes. Add the ones which aren't in the visited list to
the back of the queue.
4. Keep repeating steps 2 and 3 until the queue is empty.
PROGRAM:
import networkx as nx
graph = {
'5' : ['3','7'],
'3' : ['2', '4'],
'7' : ['8'],
'2' : [],
'4' : ['8'],
'8' : []
}
G = [Link](graph)
[Link](G, with_labels = True)
visited = [] # List for visited
nodes. queue = [] #Initialize a
queue
OUTPUT:
RESULT:
Thus the python program for implementation of graph traversal using breadth first search
was executed and verified successfully.
19 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
ALGORITHM:
PROGRAM:
# Using adjacency
list g = {
'5' : ['3','7'],
'3' : ['2', '4'],
'7' : ['8'],
'2' : [],
'4' : ['8'],
'8' : []
}
G = [Link](g)
[Link](G, with_labels = True)
visited = set()
# Set to keep track of visited nodes of graph.
20 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
OUTPUT:
RESULT:
Thus the python program for implementation of graph traversal using breadth first search was
executed and verified successfully.
21 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
ALGORITHM:
1. First, we define a function ‘dijkstra’ that takes three arguments: the graph represented as
an adjacency matrix, the starting vertex source, and the number of vertices in the graph n.
2. The function returns a list of shortest distances from the source vertex to all other vertices in
the graph.
PROGRAM:
#importing network
import networkx as nx
import pylab
import [Link] as plt
nodes_list = [1, 2, 3, 4, 5, 6, 7]
G.add_nodes_from(nodes_list
)
#Give us the shortest paths from node 1 using the weights from the
edges. p1 = nx.shortest_path(G, source=1, weight="weight")
# This will give us the length of the shortest path from node 1 to node 6.
22 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
OUTPUT:
All shortest paths from 1:{1: [1], 2: [1, 4, 2], 4: [1, 4], 5: [1, 4, 5],
7: [1, 4, 7], 3: [1, 4, 5, 3], 6: [1, 4, 7, 6]}
Shortest path from 1 to 6:[1, 4, 7, 6] Length of the shortest path:11
RESULT:
Thus the python program to find the shortest paths to other vertices using Dijkstra’s
algorithm was executed and verified successfully.
23 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
AIM:
To find the minimum cost spanning tree of a given undirected graph using Prim’s algorithm.
ALGORITHM:
PROGRAM:
import [Link] as
plt import networkx as nx
import pylab
# Add nodes
nodes_list = [1, 2, 3, 4, 5, 6, 7]
G.add_nodes_from(nodes_list
)
# Calculate a minimum spanning tree of an undirected weighted graph with the Prim
algorithm mst = nx.minimum_spanning_tree(G, algorithm='prim')
print(sorted([Link](data=True)))
24 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
OUTPUT:
[(1, 2, {'weight': 1}), (1, 4, {'weight': 4}), (2, 3, {'weight': 2}), (4, 5,
{'weight': 3}), (4, 7, {'weight': 4}), (6, 7, {'weight': 3})]
RESULT:
Thus the python program for implementation of minimum cost spanning tree of a given undirected graph
using Prim’s algorithm
25 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
AIM:
ALGORITHM:
Step1: In this program, INF represents infinity, and the floyd_algoritfhunmction takes in a is the weight of
the ed
weighted graph represented as a two-dimensional list where e[ir]t[ejx] i to vertex j.
fgroramp
Step:2 The function returns a two-dimensional list dist where dist[i][j] is the shortest path from
vertex i to vertex j.
Step:3 The algorithm first initializes the dist list with the weights of the edges in the graph. It
then uses three nested loops to find the shortest path from vertex i to vertex j through vertex k.
Step:4 If the path through k is shorter than the current shortest path from i to j, it updates dist[i][j]
with the new shortest path.
Step:5 Finally, the program calls the floyd_algorithm function on a sample input graph and prints
the resulting dist list.
PROGRAM:
INF = float('inf')
def floyd_algorithm(graph):
n = len(graph)
dist = [[INF for j in range(n)] for i in range(n)]
for i in range(n):
for j in range(n):
if graph[i][j] != 0:
dist[i][j] = graph[i][j]
for k in range(n):
for i in range(n):
for j in range(n):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return dist
26 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
# Sample input
graph = [
[0, 5, INF, 10],
[INF, 0, 3, INF],
[INF, INF, 0, 1],
[INF, INF, INF, 0]
]
result = floyd_algorithm(graph)
for row in result:
print(row)
OUTPUT:
[inf, 5, 8, 9]
[inf, inf, 3, 4]
[inf, inf, inf, 1]
[inf, inf, inf, inf]
RESULT:
Thus the python program for implementation of Floyd’s algorithm for the All-Pairs- Shortest- Paths
problem was executed and verified successfully.
27 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
ALGORITHM:
Step1: In this program, graph is a two-dimensional list representing the directed graph where
graph[i][j] is 1 if there is an edge from vertex i to vertex j, and 0 otherwise.
Step2: The warshall_algorithm function returns a two-dimensional list representing the transitive closure
of the input graph.
Step3: The algorithm first creates a copy of the input graph as the initial transitive closure. It then uses
three nested loops to update the transitive closure by checking if there is a path from vertex i to vertex j
through vertex k. If there is, it sets transitive_closure[i][j] to 1.
Step4: Finally, the program calls the warshall_algorithm function on a sample input graph and prints the
resulting transitive closure.
PROGRAM:
def warshall_algorithm(graph):
n = len(graph)
OUTPUT:
[1, 1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1,
1]
RESULT:
Thus the python program to compute the transitive closure of a given directed graph using
Warshall's algorithm was executed and verified successfully.
29 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
ALGORITHM:
1. The find_max_min function recursively divides the list into two halves until the base cases
are reached (when the list contains only one or two elements).
2. In the base case, the maximum and minimum numbers are returned.
3. In the recursive case, the maximum and minimum numbers of the left and right halves
are computed and the maximum and minimum of the whole list is returned using the max and
min
functions.
PROGRAM:
def find_max_min(arr):
if len(arr) == 1:
return arr[0], arr[0]
elif len(arr) == 2:
if arr[0] > arr[1]:
return arr[0], arr[1]
else:
return arr[1], arr[0]
else:
mid = len(arr) // 2
left_max, left_min = find_max_min(arr[:mid]) right_max, right_min =
find_max_min(arr[mid:])
return max(left_max, right_max), min(left_min, right_min)
# Example usage
arr = [3, 1, 5, 2, 9, 7]
max_num, min_num =
find_max_min(arr) print("Maximum
number:", max_num) print("Minimum
number:", min_num)
OUTPUT:
Maximum number: 9
Minimum number: 1
RESULT:
Thus the python program for find out the maximum and minimum numbers in a given list of n
numbers using the divide and conquer technique was executed and verified successfully.
30 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
ALGORITHM:
1. The program first defines the merge_sort() function which implements the Merge sort algorithm.
2. It then defines a test_merge_sort() function which generates a list of n random numbers, sorts the
list using Merge sort, and measures the time required to sort the list.
3. Finally, the program tests the test_merge_sort() function for different values of n and plots a
graph of the time taken versus n using the Matplotlib library.
PROGRAM:
import random
import time
import [Link] as plt
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
left_half = arr[:mid]
right_half = arr[mid:]
merge_sort(left_half)
merge_sort(right_half)
i=j=k=0
while i < len(left_half) and j <
len(right_half):
if left_half[i] < right_half[j]:
arr[k] = left_half[i]
i += 1
else:
arr[k] = right_half[j]
j += 1
k += 1
while i < len(left_half):
arr[k] = left_half[i]
i += 1
k += 1
while j < len(right_half):
arr[k] =
right_half[j] j += 1
k += 1
31 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
def test_merge_sort(n):
arr = [[Link](1, 100) for _ in range(n)]
start_time = [Link]()
merge_sort(arr)
end_time = [Link]()
return end_time - start_time
32 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
OUTPUT:
RESULT:
Thus the python program for Implementation of Merge sort method to sort an array
of elements and determine the time required to sort. 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 was
executed
and verified successfully.
33 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
SORT AIM:
To Implement Quick sort method to sort an array of elements and determine the time required to
sort. 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. This program generates a list of random integers of size n, sorts the list using the
quicksort function, and measures the time required to sort the list.
2. It repeats this process num_repeats times and returns the average time taken.
3. The main function of the p measure_time function for different values of n and
r gram
plots a graph of the time taken te ts the
versus
n.
4. The maximum value of n is set to max_n, and the step size between values of n is set to step_size.
5. The program uses the built-in random and time modules to generate random integers and
measure time, respectively. Additionally, the quicksort function is implemented recursively
and sorts the list in ascending order.
PROGRAM:
import random
import time
def quicksort(arr):
if len(arr) <= 1:
return arr
pivot = arr[0]
left = []
right = []
for i in range(1, len(arr)):
if arr[i] < pivot:
[Link](arr[i])
else:
[Link](arr[i])
return quicksort(left) + [pivot] + quicksort(right)
def measure_time(n, num_repeats):
times = []
for _ in range(num_repeats):
arr = [[Link](0, 1000000) for _ in
range(n)]
start_time = [Link]()
quicksort(arr)
end_time = [Link]()
34 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
[Link](end_time - start_time)
return sum(times) / len(times)
OUTPUT:
RESULT:
Thus the implementation of Quick sort method to sort an array of elements and determine the
time required to sort. 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 was executed and verified successfully.
35 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
ALGORITHM:
1. The is_safe function checks whether a queen can be placed in the current cell without
conflicting with any other queens on the board.
2. The solve_n_queens function places queens one by one in each column, starting from the leftmost
column. If all queens ar p aced successfully, it returns True. Otherwise, it backtracks and removes
the queen from the current cell and tries to place it in a different row in the same column.
3. The print_board function prints the final board configuration after all queens have been placed.
4. The n_queens function initializes the board and calls the solve_n_queens function to solve the
N Queens problem. If a solution exists, it prints the board configuration. Otherwise, it prints a
message indicating that a solution does not exist.
PROGRAM:
def n_queens(n):
# Initialize the board
board = [[0 for j in range(n)] for i in range(n)]\
if not solve_n_queens(board, 0, n):
print("Solution does not
exist.") return False
print("Solution:")
print_board(board, n)
return True
OUTPUT:
Solution:
0 0 1 0
1 0 0 0
0 0 0 1
0 1 0 0
RESULT:
Thus the python program for Implementation of N Queens problem using Backtracking Technique
was executed and verified successfully.
37 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
AIM:
To implement any scheme 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:
The following steps involved in solving TSP using branch and bound:
1. Construct a complete graph with the given cities as vertices, where the weight of each edge
is the distance between the two cities.
2. Initialize the lower bound to infinity and create an empty path.
3. Choose a starting vertex and add it to the path.
4. For each remaining vertex, compute the lower bound for the path that includes this vertex
and add it to the priority queue.
5. While the priority queue is not empty, select the path with the lowest lower bound and extend
it by adding the next vertex.
6. Update the lower bound for the new path and add it to the priority queue.
7. If all vertices have been added to the path, update the lower bound to the length of the
complete tour and update the optimal tour if the new tour is shorter.
8. Backtrack to the previous vertex and explore other paths until all paths have been explored.
PROGRAM:
import itertools
import math
import time
38 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
distance(permutation[-1], permutation[0])
# Update the shortest path if the current path is shorter if path_length < shortest_path:
shortest_path = path_length shortest_path_order = permutation
return shortest_path, shortest_path_order# Function to find the approximate solution using the nearest
neig hbor algorithm
def tsp_nearest_neighbor(cities):
# Start with the first city in the list as the current city current_city = cities[0]
visited_cities = [current_city]
# Iterate over all cities to find the nearest neighbor while len(visited_cities) <
len(cities):
nearest_neighbor = None nearest_distance =
float('inf') for city in cities:
if city not in visited_cities:
distance_to_city = distance(current_city, city) if distance_to_city <
nearest_distance:
nearest_distance = distance_to_city nearest_neighbor = city
path total_distance = 0
for i in range(len(visited_cities)-1):
total_distance += distance(visited_cities[i], visited_cities[i+1])
total_distance += distance(visited_cities[-1], visited_cities[0])
return total_distance, visited_cities
39 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
OUTPUT:
RESULT:
Thus the python program for implementation of any scheme 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 was executed and verified successfully..
40 | P a g e
lOM oARcPSD|3 1 3 1 7 4 54
ALGORITHM:
1. The partition () function takes an array arr, low index low, and high index high as input
and partitions the array around a randomly chosen pivot. It returns the index of the pivot element.
2. The randomized_select() function takes an array arr, low index low, high index high, and the
value of k as input and returns the kth smallest element in the array. It first selects a random pivot
element
using [Link]() function and partitions the array using the partition() function. Then it
recursively calls itself on e ither the left or partition depending on the position of the pivot
righ element.
3. In the main section, we define an array arr and the value of k. Then we calculate the length of
the array n and call the randomized_select() function on the array to find the kth smallest element.
PROGRAM:
import random
# Function to partition the array around a pivot def partition(arr, low, high):
i = low - 1
pivot = arr[high]
for j in range(low, high):
# Testing the
function arr = [9, 4,
2, 7, 3, 6]
k=3
n = len(arr)
result = randomized_select(arr, 0, n-1, k-1)
print(f"The {k}th smallest number is: {result}")
OUTPUT:
RESULT:
Thus the python program for implementation of randomized algorithms for finding the kth
smallest number was executed and verified successfully.
42 | P a g e