You are on page 1of 26

DESIGN & ANALYSIS OF ALGORITHM

LABORATORY
MCA03L05
Session:2022-23

Md Imran

21MCA003

COMPUTER SCIENCE & ENGINEERING DEPARTMENT

NATIONAL INSTITUTE OF TECHNOLOGY, AGARTALA

NOVEMEBER-2022
Design & Analysis of Algorithm Laboratory
(MCA03L06)
A sessional Report submitted to

National Institute of Technology, Agartala


For the partial fulfilment of the degree

Masters of Computer Application


In

Department of Computer Science & Engineering


By

Md Imran
(21MCA003)

3rd Semester
Under the supervision of

Mr. Suman Saha, Lab Assistant, CSE Department, NIT Agartala

Dr. Smita Das, Professor, CSE Department, NITAgartala

Mr. Harshad Sharma, Lab Assistant, CSE Department, NIT


Agartala
ACKNOWLEDGEMENT
First of all, I would like to thank all the faculty members at the lab Mr. Suman Saha,
for teaching me the skills required to tackle the problems and generating interest
in the subject. I would also like to thank my peers and family who we are always
ready to share their knowledge and provided support throughout this course. My
thanks and appreciation also goes to all the other non-teaching staffs of NIT
Agartala for their kind and timely support.

Name: Md Imran

Enroll. No :- 21MCA003
Sessional Report Approval
This sessional report for Design & Analysis of Algorithm Laboratory by
Md Imran(21MCA003) is approved for the partial fulfillment of the
requirements for the degree of Masters of Computer Application.

Dr. Smita Das


Professor, CSE Department

NIT Agartala

Mr. Suman Saha

Lab Assistant, CSE Department

NIT Agartala
DECLARATION
I declare that this Sessional Report represents my ideas in my own words and where
others’ ideas or words have been included. I have adequately cited and referenced
the original sources. I also declare that I have adhered to all principles of academic
honesty and integrity and have not misinterpreted or fabricated or falsified any
idea/data/fact/source in my submission. I understand that any violation of the
above will be caused for disciplinary action by the institute and can also evoke penal
action from the sources which have thus not been properly cited or from whom
proper permission has not been taken when needed.

Md Imran

21MCA003

Date: / /2022
INDEX

S. No. Experiment Name Page no.

1 i) Bubble sort
ii) Quick sort

2 i) Insertion sort
ii) Merge sort

3 0/1 Knapsack problem

4 Shortest path algorithm—Dijkstra’s Algorithm

5 Tree traversals
 Preorder
 Inorder
 Postorder

6 Linear Search

7 i) Using BFS method, print all nodes reachable from a given


starting node in a digraph.
ii) Using DFS method, check whether a given graph is connected
or not.

8 Krushkal’s Algorithm for implementation of spanning tree.

9 Using Prim’s Algorithm, construct a minimum spanning tree of a


graph.
Experiment :- 01
i) Write a program to sort a given set of elements using the bubble
sort method.

Theory: Bubble sort algorithm works by repeatedly swapping the adjacent elements.
CODE:-

#include<iostream>
using namespace std;

void bubbleSort(int a[])


{
for(int i=0;i<5;i++)
{
for(int j=0;j<(5-i-1);j++)
{
if(a[j]>a[j+1])
{
int temp = a[j]; //21MCA003-Md Imran
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}
int main()
{
cout<<"Md Imran-21MCA003"<<endl;
int array[5];
int size;
cout<<"Enter five number"<<endl;
for(int i=0;i<5;i++)
cin>>array[i];
cout<<"Before sorting"<<endl;
for(int i=0;i<5;i++)
{
cout<<array[i]<<" ";
}
bubbleSort(array);

cout<<endl<<"After Sorting"<<endl;
for(int i=0;i<5;i++)
{
cout<<array[i]<<" ";
}
return 0;
}
Conclusion:-
This algorithm is used to sort array in ascending order.
Time complexity: O(N2) Auxiliary space: O(1)
ii) Write a program to sort a given set of elements using the quick sort method.
Theory: Quick sort is a divide and conquer algorithm. It picks an element as a pivot and
partitions the given array around the picked pivot.
CODE:-
#include<bits/stdc++.h> //21MCA003—Md Imran
#include <iostream>
using namespace std;
int partition(int arr[], int start, int end)
{
int pivot = arr[start];
int count = 0;
for (int i = start + 1; i <= end; i++)
{
if (arr[i] <= pivot)
count++; }
int pivotIndex = start + count;
swap(arr[pivotIndex], arr[start]);
int i = start, j = end;
while (i < pivotIndex && j > pivotIndex) {
while (arr[i] <= pivot) {
i++;
}
while (arr[j] > pivot) {
j--;
}
if (i < pivotIndex && j > pivotIndex) {
swap(arr[i++], arr[j--]); }
}
return pivotIndex;
}
void quickSort(int arr[], int start, int end){
if (start >= end)
return;
int p = partition(arr, start, end);
quickSort(arr, start, p - 1);
quickSort(arr, p + 1, end);
}
int main()
{
int arr[] = { 9, 3, 4, 2, 1, 8 };
int n = 6;
quickSort(arr, 0, n - 1);
cout<<"Sorted array:\n";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
}
return 0;
}

Conclusion:
The key process in quick sort algorithm is partition() process to sort elements.

OUTPUT:-

Bubble sort

Quick sort
Experiment :- 02
i) Write a program to sort a given set of elements using insertion sort method.

Theory: The array is virtually split into a sorted and an unsorted part. Values from
the unsorted part are picked and placed at the correct position in the sorted part.
CODE:-
#include <bits/stdc++.h>
using namespace std;
void insertionSort(int arr[], int n)
{
int i, key, j;
for (i = 1; i < n; i++) //21MCA003-Md Imran
{
key = arr[i];
j = i - 1;
while (j >= 0 && arr[j] > key)
{
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
void printArray(int arr[], int n)
{
int i;
for (i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
}
int main()
{
int arr[] = { 12, 11, 13, 5, 6 };
int N = sizeof(arr) / sizeof(arr[0]);
cout<<"Md Imran-21MCA003"<<endl;
insertionSort(arr, N);
printArray(arr, N);

return 0;
}

Conclusion: Insertion sort takes maximum time to sort if elements are sorted in reverse.
Time complexity: O(N2) Auxiliary Space: O(1)
ii) Write a program to sort a given sets of elements using the merge sort method.
Theory:The merge sort algorithm is a sorting algorithm that is based on the Divide and
Conquer paradigm. In this algorithm, the array is initially divided into two equal halves and
then they are combined in a sorted manner.
CODE:-
#include <iostream> //21MCA003-Md Imran
using namespace std;
void merge(int array[], int const left, int const mid, int const right)
{
auto const subArrayOne = mid - left + 1;
auto const subArrayTwo = right - mid;
auto *leftArray = new int[subArrayOne],
*rightArray = new int[subArrayTwo];
for (auto i = 0; i < subArrayOne; i++)
leftArray[i] = array[left + i];
for (auto j = 0; j < subArrayTwo; j++)
rightArray[j] = array[mid + 1 + j];
auto indexOfSubArrayOne=0;
indexOfSubArrayTwo=0;
int indexOfMergedArray=left;
while (indexOfSubArrayOne < subArrayOne && indexOfSubArrayTwo < subArrayTwo)
{ if (leftArray[indexOfSubArrayOne]<= rightArray[indexOfSubArrayTwo]) {
array[indexOfMergedArray]=
leftArray[indexOfSubArrayOne]; indexOfSubArrayOne++;
}
else {
array[indexOfMergedArray]=
rightArray[indexOfSubArrayTwo]; indexOfSubArrayTwo++;
}
indexOfMergedArray++;
}
while (indexOfSubArrayOne < subArrayOne) {
array[indexOfMergedArray]=
leftArray[indexOfSubArrayOne]; indexOfSubArrayOne++;
indexOfMergedArray++;
}
while (indexOfSubArrayTwo < subArrayTwo) {
array[indexOfMergedArray]= rightArray[indexOfSubArrayTwo];
indexOfSubArrayTwo++;
indexOfMergedArray++;
}
delete[] leftArray;
delete[] rightArray;
}
void mergeSort(int array[], int const begin, int const
end){ if (begin >= end)
return;
auto mid = begin + (end - begin) / 2;
mergeSort(array, begin, mid);
mergeSort(array, mid + 1, end);
merge(array, begin, mid, end);
}
void printArray(int A[], int size){
for (auto i = 0; i < size; i++)
cout << A[i] << " ";
}
int main(){
cout<<”Md Imran-21MCA003”<<endl;
int arr[] = { 12, 11, 13, 5, 6, 7 };
auto arr_size = sizeof(arr) / sizeof(arr[0]);
cout << "Given array is \n";
printArray(arr, arr_size);
mergeSort(arr, 0, arr_size - 1);
cout << "\nSorted array is
\n";printArray(arr, arr_size);
return 0;
}
Conclusion: O(N log(N)). Merge sort is a recursive algorithm and time complexity can be expressed as
following recurrence relation:
T(n) = 2T(n/2) + θ(n)
Output:

Insertion Sort

Merge Sort
Experiment
Experiment-03
Implement 0/1 Knapsack problem using Dynamic Programming.
CODE:-
#include <bits/stdc++.h> //21MCA003-Md Imran
using namespace std;
int max(int a, int b) { return (a > b) ? a : b; }
int knapSack(int W, int wt[], int val[], int n)
{
if (n == 0 || W == 0)
return 0;
if (wt[n - 1] > W)
return knapSack(W, wt, val, n - 1);
else
return max(
val[n - 1]
+ knapSack(W - wt[n - 1],
wt, val, n - 1),
knapSack(W, wt, val, n - 1));
}
int main()
{
int val[] = { 60, 100, 120 };
int wt[] = { 10, 20, 30 };
int W = 50;
int n = sizeof(val) / sizeof(val[0]);
cout << knapSack(W, wt, val, n);
return 0;
}
Conclusion: Time complexity: O(N*W) where ‘N’ is the number of weight element and ‘W’ is capacity. As
for every weight element we traverse through all weight capacities 1<=w<=W.
Auxiliary Space: O(N*W).
The use of 2-D array of size ‘N*W’.

OUTPUT:
EXPERIMENT:- 04
Write a program to implement SHORTEST PATHS ALGORITHM.
Code:-
#include <iostream> //21MCA003-Md Imran
using namespace std;
#include <limits.h>
#define V 9
int minDistance(int dist[], bool sptSet[])
{
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
if (sptSet[v] == false && dist[v] <= min)
min = dist[v], min_index = v;
return min_index;
}
void printSolution(int dist[])
{
cout << "Vertex \t Distance from Source" << endl;
for (int i = 0; i < V; i++)
cout << i << " \t\t\t\t" << dist[i] << endl;
}
void dijkstra(int graph[V][V], int src)
{
int dist[V];
bool sptSet[V];
for (int i = 0; i < V; i++)
dist[i] = INT_MAX, sptSet[i] = false;
dist[src] = 0;
for (int count = 0; count < V - 1; count++)
{
int u = minDistance(dist, sptSet);
sptSet[u] = true;
for (int v = 0; v < V; v++)
if (!sptSet[v] && graph[u][v]
&& dist[u] != INT_MAX
&& dist[u] + graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
}
printSolution(dist);
}
int main()
{
int graph[V][V] = { { 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}};
dijkstra(graph, 0);
return 0;
}

Conclusion:
Dijkstra’s algorithm is very similar to Prim’s algorithm for minimum spanning tree.
Like Prim’s MST, generate a SPT (shortest path tree) with a given source as a root. Maintain two sets, one set contains
vertices included in the shortest-path tree, other set includes vertices not yet included in the shortest-path
shortest tree. At
every step of the algorithm, find a vertex that is in the other set (set not yet included) and has minimum distance
from the source.
Time Complexity: O(V2) Auxiliary Space: O(V)

OUTPUT:
Experiment:- 05
Write a program to implement TREE TRAVESRSALS.

CODE:-

#include <bits/stdc++.h> //21MCA003-Md Imran

using namespace std;

struct Node
{
int data;
struct Node *left, *right;
};
Node* newNode(int data)
{
Node* temp = new Node;
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
void printPreorder(struct Node* node)
{
if (node == NULL)
return;
cout << node->data << " ";
printPreorder(node->left);
printPreorder(node->right);
}
void printInorder(struct Node* node)
{
if (node == NULL)
return;
printInorder(node->left);
cout << node->data << " ";
printInorder(node->right);
}
void printPostorder(struct Node* node)
{
if (node == NULL)
return;
printPostorder(node->left);
printPostorder(node->right);
cout << node->data << " ";
}
int main()
{
struct Node* root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
cout << "\nPreorder traversal of binary tree is \n";
printPreorder(root);
cout << "\nInorder
nInorder traversal of binary tree is \n";
printInorder(root);
cout << "\nPostorder traversal of binary tree is \n";
printPostorder(root);

return 0;
}

Conclusion:
Time Complexity: O(N)
Auxiliary Space: If we don’t consider the size of the stack for function calls then O(1) otherwise O(h) where h is
the height of the tree.

OUTPUT:
Experiment:- 06

Write a program to implement linear search.


Theory: Linear Search is defined as a sequential search algorithm that starts at one end
and goes through each element of a list until the desired element is found, otherwise the
search continues till the end of the data set. It is the easiest searching algorithm.
CODE:-
#include <iostream> //21MCA003-Md Imran
using namespace std;
int search(int arr[], int N, int x)
{
int i;
for (i = 0; i < N; i++)
if (arr[i] == x)
return i;
return -1;
}
int main(void)
{
int arr[] = { 2, 3, 4, 10, 40 };
int x = 10;
int N = sizeof(arr) / sizeof(arr[0]);
int result = search(arr, N, x);
(result == -1)
? cout << "Element is not present in array"
: cout << "Element is present at index " <<
result; return 0;
}

Conclusion:
Time complexity: O(N) Auxiliary Space: O(1)

OUTPUT:-
Experiment:-07

i) Print
all the nodes reachable from a given starting node in a digraph using BFS
method. CODE:-
#include <bits/stdc++.h> //21MCA003-Md Imran
using namespace std;
class Graph
{
public:
int V;
list<int> *adj;
Graph(int );
void addEdge(int, int);
vector<int> BFS(int, int, int []); };
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V+1];
}
void Graph::addEdge(int u, int v){
adj[u].push_back(v);
adj[v].push_back(u);
}
vector<int> Graph::BFS(int componentNum, int src, int
visited[]){ queue<int> queue;
queue.push(src);
visited[src] = componentNum;
vector<int> reachableNodes;
while(!queue.empty()){
int u = queue.front();
queue.pop();
reachableNodes.push_back(u);
for (auto itr = adj[u].begin();itr != adj[u].end(); itr++){
if (!visited[*itr]){
visited[*itr] = componentNum;
queue.push(*itr);
}
}
}
return reachableNodes;
}
void displayReachableNodes(int n, unordered_map <int, vector<int> >
m){ vector<int> temp = m[n];
for (int i=0; i<temp.size(); i++)
cout << temp[i] << " ";
cout << endl;
}
void findReachableNodes(Graph g, int arr[], int n){
int V = g.V;
int visited[V+1];
memset(visited, 0, sizeof(visited));
unordered_map <int, vector<int> > m;
int componentNum = 0;
for (int i = 0 ; i < n ; i++){
int u = arr[i];
if (!visited[u]){
componentNum++;
m[visited[u]] = g.BFS(componentNum, u, visited);
}
cout << "Reachable Nodes from " << u <<" are\n";
displayReachableNodes(visited[u], m);
}
}
int main(){
int V = 7;
Graph g(V);
g.addEdge(1, 2);
g.addEdge(2, 3);
g.addEdge(3, 4);
g.addEdge(3, 1);
g.addEdge(5, 6);
g.addEdge(5, 7);
int arr[] = {2, 4, 5};
int n = sizeof(arr)/sizeof(int);
findReachableNodes(g, arr, n);
return 0;
}

Conclusion: Time Complexity Analysis:


n = Size of the given set
E = Number of Edges
V = Number of Nodes
O(V+E) for BFS
In worst case all the V nodes are displayed for each node present in the given, i.e only
one component in the graph so it takes O(n*V) time. Worst Case Time Complexity :
O(V+E) + O(n*V)

ii) Check whether a given graph is connected or not using DFS method.
#include <bits/stdc++.h> //21MCA003-Md Imran
using namespace std;
#define N 100000
vector<int> gr1[N], gr2[N];
bool vis1[N], vis2[N];
void Add_edge(int u, int v){
gr1[u].push_back(v);
gr2[v].push_back(u);
}
void dfs1(int x){
vis1[x] = true;
for (auto i : gr1[x])
if (!vis1[i])
dfs1(i);
}
void dfs2(int x){
vis2[x] = true;
for (auto i : gr2[x])
if (!vis2[i])
dfs2(i);
}
bool Is_Connected(int n){
memset(vis1, false, sizeof vis1);
dfs1(1);
memset(vis2, false, sizeof vis2);
dfs2(1);
for (int i = 1; i <= n; i++) {
if (!vis1[i] and !vis2[i])
return false;
}
return true;
}
int main(){
int n = 4;
Add_edge(1, 2);
Add_edge(1, 3);
Add_edge(2, 3);
Add_edge(3, 4);
if (Is_Connected(n))
cout << "Yes";
else
cout << "No";
return 0;
}
Conclusion: Time Complexity: O(V+E) where V is the number of vertices and E is the
number of edges.
Auxiliary Space: O(B^M), where B is the maximum branching factor of the search tree and M
is the maximum depth of the state space.

OUTPUT:-
Experiment:- 08
Implementation of Kruskal’s Algorithm for Spanning Tree.
CODE:-
#include <bits/stdc++.h> //21MCA003-Md Imran
using namespace std;
class DSU
{
int* parent;
int* rank;
public:
DSU(int n){
parent = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = -1;
rank[i] = 1;
}
}
int find(int i){
if (parent[i] == -1)
return i;

return parent[i] = find(parent[i]);


}
void unite(int x, int y){
int s1 = find(x);
int s2 = find(y);
if (s1 != s2) {
if (rank[s1] < rank[s2]) {
parent[s1] = s2;
rank[s2] += rank[s1];
}
else {
parent[s2] = s1;
rank[s1] += rank[s2];
}
}
}
};
class Graph {
vector<vector<int> > edgelist;
int V;
public:
Graph(int V) { this->V = V; }
void addEdge(int x, int y, int w)
{
edgelist.push_back({ w, x, y });
}
void kruskals_mst()
{
sort(edgelist.begin(), edgelist.end());
DSU s(V);
int ans = 0;
cout << "Following are the edges in the "
"constructed MST"
<< endl;
for (auto edge : edgelist) {
int w = edge[0];
int x = edge[1];
int y = edge[2];
if (s.find(x) != s.find(y)) {
s.unite(x, y);
ans += w;
cout << x << " -- " << y << " == " << w
<< endl;
}
}
cout << "Minimum Cost Spanning Tree: " << ans;
}
};
int main(){
Graph g(4);
g.addEdge(0, 1, 10);
g.addEdge(1, 3, 15);
g.addEdge(2, 3, 4);
g.addEdge(2, 0, 6);
g.addEdge(0, 3, 5);
g.kruskals_mst();
return 0;
}

Conclusion:
Time Complexity: O(ElogE) or O(ElogV), Sorting of edges takes O(ELogE) time. After sorting, we iterate through all
edges and apply the find-union
union algorithm. The find and union operations can take at most O(LogV) time. So overall
complexity is O(ELogE + ELogV) time. The value of E can be at most O(V2), so O(LogV) is O(LogE) the same. Therefore,
the overall time complexity is O(ElogE) or O(ElogV).
Auxiliary Space: O(V + E), where V is the number of vertices and E is the number of edges in the graph.

OUTPUT:-
Experiment:-09

Write a program for constructing a minimum cost spanning tree of a graph using Prim’s
algorithm.
CODE:-
#include <bits/stdc++.h> //21MCA003-Md Imran
using namespace std;
#define V 5
int minKey(int key[], bool mstSet[])
{
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
if (mstSet[v] == false && key[v] < min)
min = key[v], min_index = v;
return min_index;
}
void printMST(int parent[], int graph[V][V])
{
cout << "Edge \tWeight\n";
for (int i = 1; i < V; i++)
cout << parent[i] << " - " << i << " \t"
<< graph[i][parent[i]] << " \n";
}
void primMST(int graph[V][V])
{
int parent[V];
int key[V];
bool mstSet[V];
for (int i = 0; i < V; i++)
key[i] = INT_MAX, mstSet[i] = false;
key[0] = 0;
parent[0] = -1;
for (int count = 0; count < V - 1; count++)
{
int u = minKey(key, mstSet);
mstSet[u] = true;
for (int v = 0; v < V; v++)
if (graph[u][v] && mstSet[v] == false && graph[u][v] < key[v])
parent[v] = u, key[v] = graph[u][v];
}
printMST(parent, graph);

}
int main()
{
int graph[V][V] = { { 0, 2, 0, 6, 0 },
{2,0,3,8,5},
{0,3,0,0,7},
{6,8,0,0,9},
{0,5,7,9,0}};
primMST(graph);
return 0;
}

Conclusion:-
Time Complexity: O(V2), If the input graph is represented using an adjacency list, then the time complexity
of Prim’s algorithm can be reduced to O(E log V) with the help of a binary heap.
Auxiliary Space: O(V)

OUTPUT:-

You might also like