Download as pdf or txt
Download as pdf or txt
You are on page 1of 109

ALGORITHM DESIGN AND

ANALYSIS LAB
ETCS - 351

Faculty Name: Dr. Deepak Gupta Student Name: AMAN CHAUHAN

Roll No.: 14614802719

Semester: 5th

Batch: 5C7

Maharaja Agrasen Institute of Technology, PSP area,


Sector– 22, Rohini, New Delhi – 110085.
ALGORITHM DESIGN & ANALYSIS LAB
PRACTICAL RECORD

PAPER CODE: ETCS-351


NAME OF STUDENT: AMAN CHAUHAN
UNIVERSITY ROLL NO.: 14614802719
BRANCH: CSE
GROUP: 5C7

INDEX

Prog Program Name Date of Date of Marks Total Sign.


No. Performance Uploading Marks
R1 R2 R3 R4 R5
1. a) To implement the following 21/09/21
algorithm using array as a data
structure and analyze their time
complexities: Insertion sort,
Selection sort ,Bubble sort
b) To implement the following 28/09/21
algorithm using array as a data
structure and analyze their time
complexities: Radix sort, Shell
sort, Heap sort, Bucket sort
2. To implement the linear search 5/10/21
and binary search and analyse
its time complexity.
3. a) To implement the following 12/10/21
algorithm using array as a data
structure and analyze their time
complexities: Merge Sort,
Quick Sort.

b) To implement matrix 26/10/21


multiplication using strassen’s
algorithm and analyse its time
complexity.
4. a) To implement Matrix Chain 02/11/21
Multiplication.

b) To implement Longest 02/11/21


Common Subsequence.

c) To implement Optimal 09/11/21


Binary Search Tree.

d) To implement Binomial 09/11/21


Coefficient Computation.

5. a) To implement Knapsack 30/11/21


Problem.

b) To implement Activity 30/11/21


Selection Problem.

c) To implement Huffman 07/12/21


Coding and analyze its time
complexity.

d) To implement Task 07/12/21


Scheduling Problem.

6. To implement Dijkstra 7/12/21


Algorithm.

7. a) To implement Kruskal’s 14/12/21


Algorithm

b) To implement Prim’s 14/12/21


Algorithm.

8. a) To implement Naïve String 14/12/21


Matching Algorithm.

b) To implement Rabin Karp 14/12/21


String Matching Algorithm.

c) To implement Knuth Morris 14/12/21


Pratt Algorithm.
Introduction to the Lab

Lab Objective

The main objective of this lab is to ensure that students can design efficient algorithms. The
algorithm should be designed by analyzing its running time and space complexity. The emphasis
is on choosing appropriate data structures and designing correct and efficient algorithms to operate
on these data structures. It familiarizes students with some problems for which it is unknown
whether there exist efficient algorithms.

ADA LAB Course Outcomes

S.NO Course Outcomes

ETCS351.1 Analyze the time and space complexity of incremental algorithms.

ETCS351.2 Analyze and use the asymptotic behavior of Divide and Conquer approach in
designing algorithms
ETCS351.3 Apply concept of Dynamic Programming and Greedy approach to develop various
algorithms.
ETCS351.4 Development of algorithms based on Greedy Approach.

ETCS351.5 Apply different designing strategies to solve Graph Problems.

ETCS351.6 Understand and develop various String-Matching Algorithms


Name: AMAN CHAUHAN
Date: 21/09/21
Roll no.: 14614802719
EXPERIMENT-1 Group: 5C7

Aim: To implement the following algorithm using array as a data structure and analyze their time
complexities:

1. Insertion sort 2. Selection sort 3. Bubble sort

4. Radix sort 5. Shell sort 6. Heap sort 7. Bucket sort

SOURCE CODE:
1. Insertion sort:

#include<iostream>

#include <bits/stdc++.h>

using namespace std;

using namespace std :: chrono;

void insertionSort(int array[], int n)

int i, key, j;

for (i = 1; i < n; i++)

{ key = array[i];

j = i - 1;

while (j >= 0 && array[j] > key)

{ array[j + 1] = array[j];

j = j - 1;

array[j + 1] = key;

void display(int *array, int size) {


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

cout<< array[i] << " ";

cout << endl;

int main()

cout<<"Name: AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"***INSERTION SORT***\n\n"<<endl;

int n;

cout << "\nEnter the number of elements: ";

cin >> n;

int arr[n]; //create an array with given number of elements

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

arr[i]= rand()%1000;

/*display(arr, n);*/

cout << "\nArray before Sorting: ";

display(arr, n);

clock_t start,end;

start=clock();

insertionSort(arr, n);

cout << "\nArray after Sorting: ";

display(arr, n);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime : "<<duration*1000000<<" microseconds"<< endl;


}

OUTPUT:

BEST CASE

AVERAGE CASE
WORST CASE

GRAPH:

Time(in µs) Insertion sort


90000

80000

70000

60000

50000

40000

30000

20000

10000

0
50 100 200 No. of elements

No. of elements 50 100 200

Time taken (in µs) 16000 32000 78000


2. Selection sort:

#include<iostream>

#include <bits/stdc++.h>

using namespace std;

using namespace std :: chrono;

void swapping(int &a, int &b) { //swap the content of a and b

int temp;

temp = a;

a = b;

b = temp;

void display(int *array, int size) {

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

cout<< array[i] << " ";

cout << endl;

void selectionSort(int *array, int size) {

int i, j, imin;

for(i = 0; i<size-1; i++) {

imin = i; //get index of minimum data

for(j = i+1; j<size; j++)

if(array[j] < array[imin])

imin = j;

//placing in correct position

swap(array[i], array[imin]);

int main()

{
cout<<"Name: AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"***SELECTION SORT***\n\n"<<endl;

int n;

cout << "\nEnter the number of elements: ";

cin >> n;

int arr[n]; //create an array with given number of elements

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

arr[i]= rand()%1000;

cout << "\nArray before Sorting: ";

display(arr, n);

clock_t start,end;

start=clock();

selectionSort(arr, n);

cout << "\nArray after Sorting: ";

display(arr, n);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime : "<<duration*1000000<<" microseconds"<< endl;

}
OUTPUT:

BEST CASE

AVERAGE CASE
WORST CASE

GRAPH:

Time(in µs) Selection sort


90000

80000

70000

60000

50000

40000

30000

20000

10000

0
50 100 200 No. of elements

No. of elements 50 100 200

Time taken (in µs) 16000 32000 78000


3. Bubble sort:

#include<iostream>

#include<cstdlib>

#include <bits/stdc++.h>

using namespace std;

void swapping(int &a, int &b) { //swap the content of a and b

int temp;

temp = a;

a = b;

b = temp;

void display(int *array, int size) {

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

cout << array[i] << " ";

cout << endl;

void bubbleSort(int *array, int size) {

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

int swaps = 0; //flag to detect any swap is there or not

for(int j = 0; j<size-i-1; j++) {

if(array[j] > array[j+1]) { //when the current item is bigger than next

swapping(array[j], array[j+1]);

swaps = 1; //set swap flag

if(!swaps)

break; // No swap in this pass, so array is sorted

}
int main()

cout<<"Name: AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"***BUBBLE SORT***\n\n"<<endl;

int n;

cout << "\nEnter the number of elements: ";

cin >> n;

int arr[n]; //create an array with given number of elements

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

arr[i]= rand()%1000;

cout << "\nArray before Sorting: ";

display(arr, n);

clock_t start,end;

start=clock();

bubbleSort(arr, n);

cout << "\nArray after Sorting: ";

display(arr, n);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime : "<<duration*1e6<<" microseconds"<< endl;

}
OUTPUT:

BEST CASE

AVERAGE CASE
WORST CASE

GRAPH:

Time(in µs) Bubble sort


90000

80000

70000

60000

50000

40000

30000

20000

10000

0
50 100 200 No. of elements

No. of elements 50 100 200

Time taken (in µs) 15000 31000 78000


4. Radix sort:

#include<iostream>

#include <bits/stdc++.h>

using namespace std;

// A function to get maximum value in arr[]

int getMax(int arr[], int size)

int max = arr[0];

for (int i = 1; i < size; i++)

if (arr[i] > max)

max = arr[i];

return max;

void CountingSort(int arr[], int size, int div)

int output[size];

int count[10] = {0};

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

count[ (arr[i]/div)%10 ]++;

for (int i = 1; i < 10; i++)

count[i] += count[i - 1];

for (int i = size - 1; i >= 0; i--)

output[count[ (arr[i]/div)%10 ] - 1] = arr[i];

count[ (arr[i]/div)%10 ]--;


}

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

arr[i] = output[i];

void RadixSort(int arr[], int size)

int m = getMax(arr, size);

for (int div = 1; m/div > 0; div *= 10)

CountingSort(arr, size, div);

int main()

cout<<"Name: AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"***RADIX SORT***\n\n"<<endl;

int size;

cout<<"Enter the size of the array: "<<endl;

cin>>size;

int arr[size];

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

arr[i]= rand()%1000;

cout<<endl<<"Before Sorting: "<<endl;

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

{
cout<<arr[i]<<" ";

clock_t start,end;

start=clock();

RadixSort(arr, size);

cout<<endl<<"\n\nAfter Sorting: "<<endl;

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

cout<<arr[i]<<" ";

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime taken: "<<duration*1000000<<" microseconds"<< endl;

return 0;

}
OUTPUT:

BEST CASE

AVERAGE CASE
WORST CASE

GRAPH:

Time(in µs) Radix sort


90000

80000

70000

60000

50000

40000

30000

20000

10000

0
50 100 200 No. of elements

No. of elements 50 100 200

Time taken (in µs) 16000 32000 78000


5. Shell sort:

#include<iostream>

#include <bits/stdc++.h>

using namespace std;

void swapping(int &a, int &b) { //swap the content of a and b

int temp;

temp = a;

a = b;

b = temp;

void display(int *array, int size) {

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

cout << array[i] << " ";

cout << endl;

void shellSort(int *arr, int n) {

int gap, j, k;

for(gap = n/2; gap > 0; gap = gap / 2) { //initially gap = n/2,decreasing by gap /2

for(j = gap; j<n; j++) {

for(k = j-gap; k>=0; k -= gap) {

if(arr[k+gap] >= arr[k])

break;

else

swapping(arr[k+gap], arr[k]);

int main() {

cout<<"Name: AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";


cout<<"***SHELL SORT***\n\n"<<endl;

int n;

cout << "Enter the number of elements: ";

cin >> n;

int arr[n]; //create an array with given number of elements

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

arr[i]= rand()%1000;

cout << "\n\nArray before Sorting: ";

display(arr, n);

clock_t start,end;

start=clock();

shellSort(arr, n);

cout << "\n\nArray after Sorting: ";

display(arr, n);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime taken : "<<duration*1000000<<" microseconds"<< endl;

}
OUTPUT:

BEST CASE

AVERAGE CASE
WORST CASE

GRAPH:

Time(in µs) Shell sort


90000

80000

70000

60000

50000

40000

30000

20000

10000

0
50 100 200 No. of elements

No. of elements 50 100 200

Time taken (in µs) 15000 31000 78000


6. Heap sort:

#include <iostream>

#include <bits/stdc++.h>

using namespace std;

void heapify(int arr[], int n, int i)

int largest = i;

int l = 2*i + 1;

int r = 2*i + 2;

//If left child is larger than root

if (l < n && arr[l] > arr[largest])

largest = l;

//If right child largest

if (r < n && arr[r] > arr[largest])

largest = r;

//If root is nor largest

if (largest != i)

swap(arr[i], arr[largest]);

//Recursively heapifying the sub-tree

heapify(arr, n, largest);

}
void heapSort(int arr[], int n)

for (int i = n / 2 - 1; i >= 0; i--)

heapify(arr, n, i);

//One by one extract an element from heap

for (int i=n-1; i>=0; i--)

//Moving current root to end

swap(arr[0], arr[i]);

//Calling max heapify on the reduced heap

heapify(arr, i, 0);

//Function to print array

void display(int arr[], int n)

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

cout << arr[i]<<" ";

cout << "\n";

int main()

{
cout<<"Name: AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"***HEAP SORT***\n\n"<<endl;

int n;

cout<<"Enter the number of elements :";

cin>>n;

int arr[n]; //create an array with given number of elements

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

arr[i]= rand()%1000;

cout << "\n\nUnsorted array : ";

display(arr, n);

clock_t start,end;

start=clock();

heapSort(arr, n);

cout << "\n\nSorted array : ";

display(arr, n);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime taken : "<<duration*1000000<<" microseconds"<< endl;

}
OUTPUT:

BEST CASE

AVERAGE CASE
WORST CASE

GRAPH:

Time(in µs) Heap sort


70000

60000

50000

40000

30000

20000

10000

0
50 100 200 No. of elements

No. of elements 50 100 200

Time taken (in µs) 31000 31000 63000


7. Bucket sort:

#include <iostream>

#include <algorithm>

#include <vector>

#include <bits/stdc++.h>

using namespace std;

void bucketSort(float arr[], int n)

vector<float> b[n];

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

int x = n*arr[i];

b[x].push_back(arr[i]);

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

sort(b[i].begin(), b[i].end());

int index = 0;

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

for (int j = 0; j < b[i].size(); j++)

arr[index++] = b[i][j];

int main()

cout<<"Name: AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"**BUCKET SORT***\n\n"<<endl;

//float arr[] = {0.235, 0.101, 0.476, 0.7645, 0.15, 0.142};

//int n = sizeof(arr)/sizeof(arr[0]);
int n;

cout << "\nEnter the number of elements: ";

cin >> n;

srand( (unsigned)time( NULL ) );

float arr[n]; //create an array with given number of elements

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

arr[i]= (float) rand()/RAND_MAX;

cout << "\n\nBefore Sorting :\n";

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

cout << arr[i] << " ";

clock_t start,end;

start=clock();

bucketSort(arr, n);

cout << "\n\nAfter Sorting :\n";

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

cout << arr[i] << " ";

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime taken : "<<duration*1000000<<" microseconds"<< endl;

return 0;

}
OUTPUT:

BEST CASE

AVERAGE CASE
WORST CASE

GRAPH:

Time(in µs) Bucket sort


100000

90000

80000

70000

60000

50000

40000

30000

20000

10000

0
50 100 200 No. of elements

No. of elements 50 100 200

Time taken (in µs) 32000 47000 93000


VIVA - QUESTIONS

Ans) A Sorting Algorithm is used to rearrange a given array or list elements according to a comparison
operator on the elements.

Ans) The insertion sort is fast, efficient, stable while selection sort only works efficiently when the small
set of elements is involved or the list is partially previously sorted.

Ans) Quick Sort is best sorting algorithm.

Ans) Some of the sorting algorithms in data structure are :

Insertion sort, Selection sort, Bubble sort, Merge sort, Quick sort, Heap sort,Shell sort

Ans) The worst case time complexity of Insertion sort is O(N^2) The average case time complexity of
Insertion sort is O(N^2) The time complexity of the best case is O(N) .
Name: AMAN CHAUHAN
Roll no.: 14614802719
Date: 05/10/21 EXPERIMENT-2 Group: 5C7

Aim: To implement the linear search and binary search and analyse its time complexity.
SOURCE CODE:
1. Linear Search:

#include<iostream>

#include<cstdlib>

#include <bits/stdc++.h>

#include<chrono>

using namespace std;

void display(int *array, int size){

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

cout<<array[i]<<" ";

void linearsearch(int *array,int size,int key){

int i;

for(i=0;i<size;i++)

if(array[i]==key) //searching the desired element

break;

if(i<size)

cout<<"\nElement found at index: "<<i<<endl; //print the index of desired element.

else

cout<<"Element not found."<<endl;

}
int main()

cout<<"Name : AMAN CHAUHAN\nRoll no.: 14614802719\nGroup : 5C7\n\n";

int x,i,n,arr[1000]; //declaring variables

cout<<"Number of elements in array: ";

cin>>n; //input no. of elements in array

cout<<"\nRandom array elements: \n";

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

arr[i]=rand()%500; //input the elements of array

display(arr,n);

cout<<"\n\nEnter element to search: ";

cin>>x; //input the no. to search in array

clock_t start,end;

start=clock();

linearsearch(arr,n,x);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken: "<<duration*1e6<<" microseconds"<< endl;

return 0;

}
OUTPUT:
GRAPH:

Linear Search
60
54

50

40
40
Time(in µs)

30 27

20

10

0
50 100 200
No. of elements

Total no. of elements Time taken (in µs)

50 27

100 54

200 40

2. Binary Search:

#include<iostream>

#include<bits/stdc++.h>

#include<chrono>

#include<cstdlib>

using namespace std;

int binaryiter(int array[], int start_index, int end_index, int key)

{
while (start_index <= end_index){

int middle = start_index + (end_index - start_index )/2;

if(array[middle] == key)

return middle;

if(array[middle] < key)

start_index = middle + 1;

else

end_index = middle - 1;

return -1;

void binaryrecurssive(int array[], int low, int high, int key)

int mid;

if (low > high)

cout<<"\nKey not found\n";

return;

mid = (low + high) / 2;

if (array[mid] == key)

cout<<"\nElement found at index: "<<mid<<endl;

else if (array[mid] > key)

binaryrecurssive(array, low, mid - 1, key);


}

else if (array[mid] < key)

binaryrecurssive(array, mid + 1, high, key);

void displayarray(int *array,int size)

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

cout<<array[i]<<" ";

int main()

cout<<"Name : AMAN CHAUHAN\nRoll no.: 14614802719\nGroup : 5C7\n\n";

int i,n, x, arr[1000];

cout<<"Enter the number of elements in array : ";

cin>>n;

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

arr[i]=rand()%500;

sort(arr,arr+n);

cout<<"\n\nArray is : ";

displayarray(arr,n);
cout<<"\n\nEnter the Element to search : ";

cin>>x;

clock_t start,end;

start=clock();

cout<<"\n\nIterative method : ";

int found_index = binaryiter(arr, 0, n-1, x);

if(found_index == -1 ) {

cout<<"\nElement not found in the array ";

else {

cout<<"\nElement found at index : "<<found_index;

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime : "<<duration*1e6<<" microseconds"<< endl;

clock_t start1,end1;

start1=clock();

cout<<"\n\nRecursive method : ";

binaryrecurssive(arr, 0, n, x);

end1=clock();

double duration1=double(end1-start1)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime : "<<duration1*1e6<<" microseconds"<< endl;


return 0;

OUTPUT:
GRAPH:

Binary Search
30
27

24 24
25
21

20
Time(in µs)

15
15 Iterative
Recursion

10 8

0
50 100 200
No. of elements

Method Total no. of elements Time taken (in µs)

Iterative 50 24

Iterative 100 24

Iterative 200 27

Recursion 50 8

Recursion 100 15

Recursion 200 21
VIVA - QUESTIONS

Ans) The sequential search is also known as linear search.

Ans) The primary condition for binary search is that the array should be already sorted. If not so then the
array must be sorted first.

Ans) Binary search works on the principle of divide and conquer. Binary search looks for a particular
element by comparing the middle most item of the Collection.

Ans) Binary search is more efficient as it can search a large data in less time.
Name: AMAN CHAUHAN
Roll no.: 14614802719
Date: 26/10/21 EXPERIMENT-3 Group: 5C7

Aim: a) To implement the following algorithm using array as a data structure and analyze their time
complexities: Merge Sort, Quick Sort.

b) To implement matrix multiplication using strassen’s algorithm and analyse its time complexity.

SOURCE CODE:
a) Sorting algorithms

i) Merge Sort

#include <bits/stdc++.h>

using namespace std;

void merge(int arr[], int l, int m, int r)

int i, j, k;

int n1 = m - l + 1;

int n2 = r - m;

int L[n1], R[n2];

for (i = 0; i < n1; i++)

L[i] = arr[l + i];

for (j = 0; j < n2; j++)

R[j] = arr[m + 1+ j];

i = 0; j = 0; k = l;

while (i < n1 && j < n2)

if (L[i] <= R[j])

{ arr[k] = L[i];

i++;

else{arr[k] = R[j];
j++;

k++;

while (i < n1)

arr[k] = L[i];

i++;

k++;

while (j < n2)

arr[k] = R[j];

j++;

k++;

void mergeSort(int arr[], int l, int r)

if (l < r)

int m = l+(r-l)/2;

mergeSort(arr, l, m);

mergeSort(arr, m+1, r);

merge(arr, l, m, r);

void display(int *array, int size) {


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

cout << array[i] << " ";

cout << endl;

int main()

cout<<"Name: AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"***MERGE SORT***\n\n"<<endl;

int n;

cout << "\nEnter the number of elements: ";

cin >> n;

int arr[n]; //create an array with given number of elements

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

arr[i]= rand()%1000;

cout << "\nArray before Sorting: ";

display(arr, n);

clock_t start,end;

start=clock();

mergeSort(arr,0,n-1);

cout << "\nArray after Sorting: ";


display(arr, n);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime taken: "<<duration*1e6<<" microseconds"<< endl;

OUTPUT:
ii) Quick Sort

#include <bits/stdc++.h>

using namespace std;

int partition (int arr[], int low, int high)

int pivot = arr[high];

int i = (low - 1);

for (int j = low; j <= high - 1; j++)

{if (arr[j] < pivot)

i++;

swap(arr[i], arr[j]);

swap(arr[i + 1], arr[high]);

return (i + 1);

void quickSort(int arr[], int low, int high)

if (low < high)

int pi = partition(arr, low, high);

quickSort(arr, low, pi - 1);

quickSort(arr, pi + 1, high);

void display(int *array, int size) {


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

cout << array[i] << " ";

cout << endl;

int main()

cout<<"Name: AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"***QUICK SORT***\n\n"<<endl;

int n;

cout << "\nEnter the number of elements: ";

cin >> n;

int arr[n]; //create an array with given number of elements

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

arr[i]= rand()%1000;

cout << "\nArray before Sorting: ";

display(arr, n);

clock_t start,end;

start=clock();

quickSort(arr,0,n-1);

cout << "\nArray after Sorting: ";

display(arr, n);

end=clock();
double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime taken: "<<duration*1e6<<" microseconds"<< endl;

OUTPUT:

GRAPH:
Time in us

35000

30000

25000

Merge sort
20000
Quick sort

15000

10000

5000

0
50 50 No. of Elements
b) Strassen’s Algorithm

#include<iostream>

#include<bits/stdc++.h>

using namespace std;

int main()

cout<<"Name : AMAN CHAUHAN\nRoll no.: 14614802719\nGroup : 5C7\n\n";

int a[2][2], b[2][2], c[2][2], i, j;

int p1, p2, p3, p4 , p5, p6, p7;

cout<<"Enter the 4 elements of first matrix: ";

for(i = 0;i < 2; i++)

for(j = 0;j < 2; j++)

cin>>a[i][j];

cout<<"\n\nEnter the 4 elements of second matrix: ";

for(i = 0; i < 2; i++)

for(j = 0;j < 2; j++)

cin>>b[i][j];

cout<<"\nThe first matrix is\n";

for(i = 0; i < 2; i++){

cout<<"\n";

for(j = 0; j < 2; j++)

cout<<a[i][j]<<"\t";

cout<<"\n\nThe second matrix is\n";


for(i = 0;i < 2; i++){

cout<<"\n";

for(j = 0;j < 2; j++)

cout<<b[i][j]<<"\t";

clock_t start,end;

start=clock();

p5= (a[0][0] + a[1][1]) * (b[0][0] + b[1][1]);

p3= (a[1][0] + a[1][1]) * b[0][0];

p1= a[0][0] * (b[0][1] - b[1][1]);

p4= a[1][1] * (b[1][0] - b[0][0]);

p2= (a[0][0] + a[0][1]) * b[1][1];

p7= (a[0][0] - a[1][0]) * (b[0][0]+b[0][1]);

p6= (a[0][1] - a[1][1]) * (b[1][0]+b[1][1]);

c[0][0] = p5 + p4- p2 + p6;

c[0][1] = p1 + p2;

c[1][0] = p3 + p4;

c[1][1] = p5 + p1 - p3 - p7;

cout<<"\n\nAfter multiplication using Strassen's algorithm \n";

for(i = 0; i < 2 ; i++){

cout<<"\n";

for(j = 0;j < 2; j++)

cout<<c[i][j]<<"\t";

end=clock();
double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken: "<<duration*1e6<<" microseconds"<< endl;

cout<<"\n\n";

return 0;

OUTPUT:
VIVA – QUESTIONS

Ans) A Sorting Algorithm is used to rearrange a given array or list elements according to a comparison
operator on the elements.

Ans) Divide and Conquer Technique is used in Merge sort.

Ans) Time complexity of Merge Sort is O(n*Log n) in all the 3 cases

Ans) The main difference between quicksort and merge sort is that the quicksort sorts the elements by
comparing each element with an element called a pivot while merge sort divides the array into two
subarrays again and again until one element is left.

Ans) Quick Sort is best sorting algorithm.


Name: AMAN CHAUHAN
Roll no.: 14614802719
Date: 02/11/21 EXPERIMENT-4 Group: 5C7

Aim: a) To implement Matrix Chain Multiplication.


b) To implement Longest Common Subsequence.

c) To implement Optimal Binary Search Tree.

d) To implement Binomial Coefficient Computation.

SOURCE CODE:
a) Matrix Chain Multiplication

#include<iostream>

#include<limits.h>

using namespace std;

// Matrix Ai has dimension p[i-1] x p[i] for i = 1..n

int MatrixChainMultiplication(int p[], int n)

int m[n][n];

int i, j, k, L, q;

for (i=1; i<n; i++)

m[i][i] = 0; //number of multiplications are 0(zero) when there is only one matrix

//Here L is chain length. It varies from length 2 to length n.

for (L=2; L<n; L++)

for (i=1; i<n-L+1; i++)

j = i+L-1;

m[i][j] = INT_MAX; //assigning to maximum value


for (k=i; k<=j-1; k++)

q = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];

if (q < m[i][j])

m[i][j] = q; //if number of multiplications found less that number will be updated.

return m[1][n-1]; //returning the final answer which is M[1][n]

int main()

cout<<"Name:AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"MATRIX CHAIN MULTIPLICATION \n\n";

int n,i;

cout<<"Enter number of matrices: ";

cin>>n;

n++;

int arr[n];

cout<<"\n\nEnter dimensions- \n";

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

cout<<"Enter d"<<i<<" : ";

cin>>arr[i];

int size = sizeof(arr)/sizeof(arr[0]);

clock_t start,end;

start=clock();

cout<<"\nMinimum number of multiplications is : "<<MatrixChainMultiplication(arr, size)<<"\n\n";

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken : "<<duration*1000000<<" microseconds"<<"\n\n";

return 0;

OUTPUT:
b) Longest Common Subsequence

#include<bits\stdc++.h>

using namespace std;

void lcsAlgo(char *S1, char *S2, int m, int n) {

int LCS_table[m + 1][n + 1];

// Building the mtrix in bottom-up way

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

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

if (i == 0 || j == 0)

LCS_table[i][j] = 0;

else if (S1[i - 1] == S2[j - 1])

LCS_table[i][j] = LCS_table[i - 1][j - 1] + 1;

else

LCS_table[i][j] = max(LCS_table[i - 1][j], LCS_table[i][j - 1]);

int index = LCS_table[m][n];

char lcsAlgo[index + 1];

lcsAlgo[index] = '\0';

int i = m, j = n;

while (i > 0 && j > 0) {

if (S1[i - 1] == S2[j - 1]) {

lcsAlgo[index - 1] = S1[i - 1];

i--;

j--;

index--;

else if (LCS_table[i - 1][j] > LCS_table[i][j - 1])

i--;

else
j--;

cout << "S1 : " << S1 << "\n\nS2 : " << S2 << "\n\nLCS: " << lcsAlgo << "\n\n";

int main(){ cout<<"Name:AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"LARGEST COMMON SUBSEQUENCE \n\n";

char S1[50] = "ACADB";

char S2[50] = "CBDA";

int m = strlen(S1);

int n = strlen(S2);

clock_t start,end;

start=clock();

lcsAlgo(S1, S2, m, n);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken : "<<duration*1000000<<" microseconds"<<"\n\n";

OUTPUT:
c) Optimal Binary Search Tree

#include <bits/stdc++.h>

using namespace std;

int sum(int frequency[], int i, int j)

int sum = 0;

for (int x = i; x <= j; x++)

sum += frequency[x];

return sum;

int optimalCost(int frequency[], int i, int j)

if (j < i)

return 0;

if (j == i)

return frequency[i];

int frequencySum = sum(frequency, i, j);

int min = INT_MAX;

for (int r = i; r <= j; ++r)

int cost = optimalCost(frequency, i, r - 1) + optimalCost(frequency, r + 1, j);

if (cost < min)

min = cost;

return min + frequencySum;

int optimalSearchTree(int keys[], int frequency[], int n)

return optimalCost(frequency, 0, n - 1);


}

int main()

cout<<"Name:AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"OPTIMAL BINARY SEARCH TREE \n\n";

int keys[] = {10, 12, 20};

int frequency[] = {34, 8, 50};

int n = sizeof(keys) / sizeof(keys[0]);

clock_t start,end;

start=clock();

cout << "\n\nCost of Optimal BST is : " << optimalSearchTree(keys, frequency, n)<<"\n\n";

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken : "<<duration*1000000<<" microseconds"<<"\n\n"; }

OUTPUT:
d) Binomial Coefficient Computation

#include <bits/stdc++.h>

using namespace std;

int binomialCoeff(int n, int k)

if (k == 0 || k == n)

return 1;

return binomialCoeff(n - 1, k - 1) +

binomialCoeff(n - 1, k);

int main()

cout<<"Name: AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

cout<<"BINOMIAL COEFFICIENT COMPUTAION \n\n";

int n, k;

cout<<"Enter the value of n : ";

cin>>n;

cout<<"\nEnter the value of k : ";

cin>>k;

clock_t start,end;

start=clock();

cout << "\n\nValue of C("<<n<<", "<<k<<") is : " << binomialCoeff(n, k);

end=clock();
double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken : "<<duration*1000000<<" microseconds"<<"\n\n";

return 0;

OUTPUT:

VIVA – QUESTIONS

Ans) Dynamic Programming (DP) is an algorithmic technique for solving an optimization problem by
breaking it down into simpler subproblems and utilizing the fact that the optimal solution to the overall
problem depends upon the optimal solution to its subproblems.

Ans) Matrix chain multiplication is an optimization problem concerning the most efficient way to
multiply a given sequence of matrices. The problem is not actually to perform the multiplications, but
merely to decide the sequence of the matrix multiplications involved. It is a Method under Dynamic
Programming in which previous output is taken as input for next.

Here, Chain means one matrix's column is equal to the second matrix's row (always).

Time complexity of matrix chain multiplication using dynamic programming is O(n2)


Ans) The longest common subsequence problem is the problem of finding the longest subsequence
common to all sequences in a set of sequences.

Time complexity of Longest common subsequence using dynamic programming is O(n*m)

Ans) An optimal binary search tree (Optimal BST), sometimes called a weight-balanced binary tree, is a
binary search tree which provides the smallest possible search time (or expected search time) for a given
sequence of accesses.

Ans) Recursion: It is repeated application of the same procedure on subproblems of the same type of a
problem.

Dynamic programming: It involves caching the results of the subproblems of a problem, so that every
subproblem is solved only once.
Name: AMAN CHAUHAN
Roll no.: 14614802719
Date: 30/11/21 EXPERIMENT- 5 Group: 5C7

Aim: a) To implement Knapsack Problem.


b) To implement Activity Selection Problem.

c) To implement Huffman Coding and analyze its time complexity.

d) To implement Task Scheduling Problem.

SOURCE CODE:
a) i) 0-1 Knapsack Problem using dynamic programming

#include <iostream>

using namespace std;

int max(int a, int b)

return (a > b) ? a : b;

// Returns the maximum value that can be put in a knapsack of capacity W

int knapSack(int W, int wt[], int val[], int n)

int i, w;

int K[n + 1][W + 1];

// Build table K[][] in bottom up manner

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

for (w = 0; w <= W; w++)

if (i == 0 || w == 0)

K[i][w] = 0;

else if (wt[i - 1] <= w)


K[i][w]

= max(val[i - 1] + K[i - 1][w - wt[i - 1]], K[i - 1][w]);

else

K[i][w] = K[i - 1][w];

return K[n][W];

int main()

cout << "\nEnter the number of items in a Knapsack:";

int n, W;

cin >> n;

int val[n], wt[n];

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

cout << "\nEnter value and weight for item " << i << ":";

cin >> val[i];

cin >> wt[i];

// int val[] = { 60, 100, 120 };

// int wt[] = { 10, 20, 30 };

// int W = 50;

cout << "\nEnter the capacity of knapsack: ";

cin >> W;

clock_t start,end;

start=clock();

cout <<"\nThe min. weight should be: "<< knapSack(W, wt, val, n);
end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken : "<<duration*1000000<<" microseconds"<<"\n\n"; return 0;

OUTPUT:

ii) Fractional Knapsack Problem

#include<iostream>

using namespace std;

float wt[20],pt[20],profit=0.0,y[20];

int n,i,w,temp,j,u;

class fractional_knapsack

public:

void getdata()

cout<<"Enter the max weight of the bag : "<<endl;

cin>>w;
cout<<"\nHow many objects you want to store inside the bag : "<<endl;

cin>>n;

cout<<"\nEnter the wt of the objects : \n";

for(i=1;i<=n;i++)

cin>>wt[i];

cout<<"\nEnter the profit of the objects : "<<endl;

for(i=1;i<=n;i++)

cin>>pt[i];

void sortdata()

for(i=1;i<=n;i++)

for(j=1;j<=n;j++)

if((pt[j]/wt[j])<(pt[j+1]/wt[j+1]))

temp=pt[j];

pt[j]=pt[j+1];

pt[j+1]=temp;

temp=wt[j];

wt[j]=wt[j+1];

wt[j+1]=temp;

}
}

void calculation()

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

y[i]=0.0;

u=w;

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

if(wt[i]>u)

break;

y[i]=1.0;

u=u-wt[i];

if(i<n)

y[i]=u/wt[i];

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

profit=profit+(pt[i]*y[i]);

void displaydata()

cout<<"-------------------------------------------\n";

cout<<"obj_no weigth profit\t\n";

cout<<"-------------------------------------------\n";

for(i=1;i<=n;i++)

cout<<i<<"\t"<<wt[i]<<"\t"<<pt[i]<<"\t"<<endl;

cout<<"\nMAXIMUM PROFIT:"<<profit;

};
int main()

{ cout<<"Name:AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

fractional_knapsack obj;

obj.getdata();

clock_t start,end;

start=clock();

obj.sortdata();

obj.calculation();

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

obj.displaydata();

cout <<"\n\nTime Taken : "<<duration*1000000<<" microseconds"<<n\n";

return 0;

OUTPUT:
b) Activity Selection Problem

#include <bits/stdc++.h>

using namespace std;

void printMaxActivities(int s[], int f[], int n)

int i, j;

cout <<"Following activities are selected : ";

// The first activity always gets selected

i = 0;

cout <<" "<< i;

// Consider rest of the activities

for (j = 1; j < n; j++)

// If this activity has start time greater than or

// equal to the finish time of previously selected

// activity, then select it

if (s[j] >= f[i])

cout <<" " << j;

i = j;

int main()

{ cout<<"Name:AMAN CHAUHAN\nRoll no.: 14614802719\nGroup: 5C7\n\n";

int s[] = {1, 3, 0, 5, 8, 5};

int f[] = {2, 4, 6, 7, 9, 9}; //should be increasing order


int n = sizeof(s)/sizeof(s[0]);

clock_t start,end;

start=clock();

printMaxActivities(s, f, n);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken : "<<duration*1000000<<" microseconds"<<"\n\n";

return 0;

OUTPUT:
c) Huffman Coding

#include <iostream>

#include <cstdlib>

using namespace std;

// This constant can be avoided by explicitly calculating height of Huffman Tree

#define MAX_TREE_HT 100

// A Huffman tree node

struct MinHeapNode {

char data; // One of the input characters

unsigned freq; // Frequency of the character

struct MinHeapNode *left, *right; // Left and right child of this node

};

// A Min Heap: Collection of min-heap (or Huffman tree) nodes

struct MinHeap {

unsigned size; // Current size of min heap

unsigned capacity; // capacity of min heap

struct MinHeapNode** array; // Array of minheap node pointers

};

// A utility function allocate a new min heap node with given character and frequency of the character

struct MinHeapNode* newNode(char data, unsigned freq)

{
struct MinHeapNode* temp

= (struct MinHeapNode*)malloc

(sizeof(struct MinHeapNode));

temp->left = temp->right = NULL;

temp->data = data;

temp->freq = freq;

return temp;

// A utility function to create a min heap of given capacity

struct MinHeap* createMinHeap(unsigned capacity)

struct MinHeap* minHeap

= (struct MinHeap*)malloc(sizeof(struct MinHeap));

// current size is 0

minHeap->size = 0;

minHeap->capacity = capacity;

minHeap->array

= (struct MinHeapNode**)malloc(minHeap->

capacity * sizeof(struct MinHeapNode*));

return minHeap;

}
// A utility function to swap two min heap nodes

void swapMinHeapNode(struct MinHeapNode** a,

struct MinHeapNode** b)

struct MinHeapNode* t = *a;

*a = *b;

*b = t;

// The standard minHeapify function.

void minHeapify(struct MinHeap* minHeap, int idx)

int smallest = idx;

int left = 2 * idx + 1;

int right = 2 * idx + 2;

if (left < minHeap->size && minHeap->array[left]->

freq < minHeap->array[smallest]->freq)

smallest = left;

if (right < minHeap->size && minHeap->array[right]->

freq < minHeap->array[smallest]->freq)

smallest = right;

if (smallest != idx) {

swapMinHeapNode(&minHeap->array[smallest],

&minHeap->array[idx]);
minHeapify(minHeap, smallest);

// A utility function to check if size of heap is 1 or not

int isSizeOne(struct MinHeap* minHeap)

return (minHeap->size == 1);

// A standard function to extract minimum value node from heap

struct MinHeapNode* extractMin(struct MinHeap* minHeap)

struct MinHeapNode* temp = minHeap->array[0];

minHeap->array[0]

= minHeap->array[minHeap->size - 1];

--minHeap->size;

minHeapify(minHeap, 0);

return temp;

// A utility function to insert a new node to Min Heap

void insertMinHeap(struct MinHeap* minHeap,

struct MinHeapNode* minHeapNode)

++minHeap->size;

int i = minHeap->size - 1;
while (i && minHeapNode->freq < minHeap->array[(i - 1) / 2]->freq) {

minHeap->array[i] = minHeap->array[(i - 1) / 2];

i = (i - 1) / 2;

minHeap->array[i] = minHeapNode;

// A standard function to build min heap

void buildMinHeap(struct MinHeap* minHeap)

int n = minHeap->size - 1;

int i;

for (i = (n - 1) / 2; i >= 0; --i)

minHeapify(minHeap, i);

// A utility function to print an array of size n

void printArr(int arr[], int n)

int i;

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

cout<< arr[i];

cout<<"\n";

}
// Utility function to check if this node is leaf

int isLeaf(struct MinHeapNode* root)

return !(root->left) && !(root->right);

// Creates a min heap of capacity equal to size and inserts all character of data[] in min heap. Initially
size of min heap is equal to capacity

struct MinHeap* createAndBuildMinHeap(char data[], int freq[], int size)

struct MinHeap* minHeap = createMinHeap(size);

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

minHeap->array[i] = newNode(data[i], freq[i]);

minHeap->size = size;

buildMinHeap(minHeap);

return minHeap;

// The main function that builds Huffman tree

struct MinHeapNode* buildHuffmanTree(char data[], int freq[], int size)

struct MinHeapNode *left, *right, *top;

// Step 1: Create a min heap of capacity equal to size. Initially, there are modes equal to size.

struct MinHeap* minHeap = createAndBuildMinHeap(data, freq, size);

// Iterate while size of heap doesn't become 1

while (!isSizeOne(minHeap)) {
// Step 2: Extract the two minimum freq items from min heap

left = extractMin(minHeap);

right = extractMin(minHeap);

// Step 3: Create a new internal node with frequency equal to the

// sum of the two nodes frequencies.Make the two extracted node as left and right children of
this new node.

// Add this node to the min heap

// '$' is a special value for internal nodes, not used

top = newNode('$', left->freq + right->freq);

top->left = left;

top->right = right;

insertMinHeap(minHeap, top);

// Step 4: The remaining node is the root node and the tree is complete.

return extractMin(minHeap);

// Prints huffman codes from the root of Huffman Tree. It uses arr[] to store codes

void printCodes(struct MinHeapNode* root, int arr[], int top)

// Assign 0 to left edge and recur

if (root->left) {

arr[top] = 0;

printCodes(root->left, arr, top + 1);

// Assign 1 to right edge and recur


if (root->right) {

arr[top] = 1;

printCodes(root->right, arr, top + 1);

// If this is a leaf node, thenmit contains one of the input

// characters, print the character and its code from arr[]

if (isLeaf(root)) {

cout<< root->data <<": ";

printArr(arr, top);

// The main function that builds a Huffman Tree and print codes by traversing the built Huffman Tree

void HuffmanCodes(char data[], int freq[], int size)

// Construct Huffman Tree

struct MinHeapNode* root = buildHuffmanTree(data, freq, size);

// Print Huffman codes using the Huffman tree built above

int arr[MAX_TREE_HT], top = 0;

printCodes(root, arr, top);

int main()

{ cout<<"Name : AMAN CHAUHAN\nRoll no.: 14614802719\nGroup : 5C7\n\n";

char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };

int freq[] = { 5, 9, 12, 13, 16, 45 };

int size = sizeof(arr) / sizeof(arr[0]);

clock_t start,end;

start=clock();
HuffmanCodes(arr, freq, size);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken: "<<duration*1e6<<" microseconds"<< endl<<"\n\n";

return 0;

OUTPUT:
d) Task Scheduling Problem

#include<iostream>

#include<algorithm>

using namespace std;

int findmachine(int arr[],int dep[],int n)

int plat_needed=1,result=1;

int i=1,j=0;

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

plat_needed=1;

for(int j=i+1;j<n;j++)

if( (arr[i]>=arr[j] && arr[i]<=dep[j]) || (arr[j]>=arr[i] && arr[j]<=dep[i]) )

plat_needed++;

result = max(result,plat_needed);

return result;

int main()

cout<<"Name : AMAN CHAUHAN\nRoll no.: 14614802719\nGroup : 5C7\n\n";

int start[] = {900,940,950,1100,1500,1800};


int finish[] = {910,1200,1120,1130,1900,2000};

int n = sizeof(start)/sizeof(start[0]);

cout<<"Minimum Number of Machines required = "<<findmachine(start,finish,n)<<endl;

return 0;

OUTPUT:
VIVA – QUESTIONS

Ans) Dynamic Programming (DP) is an algorithmic technique for solving an optimization problem by
breaking it down into simpler subproblems and utilizing the fact that the optimal solution to the overall
problem depends upon the optimal solution to its subproblems.

Ans) The knapsack problem is a problem in combinatorial optimization: Given a set of items, each with
a weight and a value, determine the number of each item to include in a collection so that the total
weight is less than or equal to a given limit and the total value is as large as possible.

Ans) The Activity Selection Problem is an optimization problem which deals with the selection of non-
conflicting activities that needs to be executed by a single person or machine in a given time frame.

Each activity is marked by a start and finish time. Greedy technique is used for finding the solution since
this is an optimization problem.

Ans) The process of deciding which task will utilize the cpu time is called task scheduling. The
scheduling of the task may be on the basis of their priorities.

Ans) Greedy Method: In a greedy Algorithm, we make whatever choice seems best at the moment and
then solve the sub-problems arising after the choice is made.

Dynamic programming: It involves caching the results of the subproblems of a problem, so that every
subproblem is solved only once.
Name: AMAN CHAUHAN
Roll no.: 14614802719
Date: 07/12/21 EXPERIMENT- 6 Group: 5C7

Aim: To implement Dijkstra Algorithm.


SOURCE CODE:
#include <limits.h>

#include <iostream>

using namespace std;

// Number of vertices in the graph

#define V 9

// A utility function to find the vertex with minimum distance value, from

// the set of vertices not yet included in shortest path tree

int minDistance(int dist[], bool sptSet[])

{ // Initialize min value

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;

// A utility function to print the constructed distance array

int printSolution(int dist[], int n)

cout<<"Vertex \t Distance from Source\n";

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

cout<<i<<"\t\t"<<dist[i]<<"\n";
}

// Function that implements Dijkstra's single source shortest path algorithm

// for a graph represented using adjacency matrix representation

void dijkstra(int graph[V][V], int src)

int dist[V]; // The output array. dist[i] will hold the shortest

// distance from src to i

bool sptSet[V]; // sptSet[i] will be true if vertex i is included in shortest

// path tree or shortest distance from src to i is finalized

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

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

dist[i] = INT_MAX, sptSet[i] = false;

// Distance of source vertex from itself is always 0

dist[src] = 0;

// Find shortest path for all vertices

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

// Pick the minimum distance vertex from the set of vertices not

// yet processed. u is always equal to src in the first iteration.

int u = minDistance(dist, sptSet);

// Mark the picked vertex as processed

sptSet[u] = true;

// Update dist value of the adjacent vertices of the picked vertex.

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


// Update dist[v] only if is not in sptSet, there is an edge from

// u to v, and total weight of path from src to v through u is

// smaller than current value of dist[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];

// print the constructed distance array

printSolution(dist, V);

int main()

cout<<"Name : AMAN CHAUHAN\nRoll no.: 14614802719\nGroup : 5C7\n\n";

cout<<"DIJKSTRA ALGORITHM:\n\n";

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 } };

clock_t start,end;

start=clock();
dijkstra(graph, 0);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken: "<<duration*1e6<<" microseconds"<< endl;

return 0;

OUTPUT:
VIVA – QUESTIONS

Ans) A greedy algorithm is an algorithmic strategy that makes the best optimal choice at each small
stage with the goal of this eventually leading to a globally optimum solution. This means that the
algorithm picks the best solution at the moment without regard for consequences.

Ans) Dijkstra's algorithm is an algorithm for finding the shortest paths between nodes in a graph,

Ans) Time Complexity of Dijkstra's Algorithm is O ( V2 ) but with min-priority queue it drops down to
O ( V + E l o g V ).

Ans) Dijkstra's algorithm work in both directed and undirected graphs, because you simply add edges
nodes into the PriorityQueue when you have an edge to travel to from your adjacency list.

Ans) Greedy Method: In a greedy Algorithm, we make whatever choice seems best at the moment and
then solve the sub-problems arising after the choice is made.

Dynamic programming: It involves caching the results of the subproblems of a problem, so that every
subproblem is solved only once.
Date: 14/12/21 EXPERIMENT- 7

Aim: a) To implement Kruskal’s Algorithm.


b) To implement Prim’s Algorithm

SOURCE CODE:
a) Kruskal’s Algorithm.

#include<bits/stdc++.h>

using namespace std;

// Creating shortcut for an integer pair

typedef pair<int, int> iPair;

// Structure to represent a graph

struct Graph

int V, E;

vector< pair<int, iPair> > edges;

// Constructor

Graph(int V, int E)

this->V = V;

this->E = E;

//function to add an edge

void addEdge(int u, int v, int w)

edges.push_back({w, {u, v}});

// Function to find MST using Kruskal's MST algorithm


int kruskalMST();

};

// To represent Disjoint Sets

struct DisjointSets

int *parent, *rnk;

int n;

// Constructor.

DisjointSets(int n)

{ // Allocate memory

this->n = n;

parent = new int[n+1];

rnk = new int[n+1];

// Initially, all vertices are in

// different sets and have rank 0.

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

rnk[i] = 0;

//every element is parent of itself

parent[i] = i;

// Find the parent of a node 'u' Path Compression

int find(int u)

{ /* Make the parent of the nodes in the path

from u--> parent[u] point to parent[u] */

if (u != parent[u])

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

// Union by rank

void merge(int x, int y)

x = find(x), y = find(y);

/* Make tree with smaller height a subtree of the other tree */

if (rnk[x] > rnk[y])

parent[y] = x;

else // If rnk[x] <= rnk[y]

parent[x] = y;

if (rnk[x] == rnk[y])

rnk[y]++;

};

/* Functions returns weight of the MST*/

int Graph::kruskalMST()

int mst_wt = 0; // Initialize result

// Sort edges in increasing order on basis of cost

sort(edges.begin(), edges.end());

// Create disjoint sets

DisjointSets ds(V);

// Iterate through all sorted edges

vector< pair<int, iPair> >::iterator it;

for (it=edges.begin(); it!=edges.end(); it++)

int u = it->second.first;
int v = it->second.second;

int set_u = ds.find(u);

int set_v = ds.find(v);

// Check if the selected edge is creating a cycle or not (Cycle is created if u and v belong to same set)

if (set_u != set_v)

// Current edge will be in the MST so print it

cout << u << " - " << v << endl;

// Update MST weight

mst_wt += it->first;

// Merge two sets

ds.merge(set_u, set_v);

return mst_wt;

int main()

{ cout<<"Name : AMAN CHAUHAN\nRoll no.: 14614802719\nGroup : 5C7\n\n";

cout<<"KRUSKAL's ALGORITHM:\n\n";

int V = 9, E = 14;

Graph g(V, E);

g.addEdge(0, 1, 4);

g.addEdge(0, 7, 8);

g.addEdge(1, 2, 8);

g.addEdge(1, 7, 11);

g.addEdge(2, 3, 7);

g.addEdge(2, 8, 2);
g.addEdge(2, 5, 4);

g.addEdge(3, 4, 9);

g.addEdge(3, 5, 14);

g.addEdge(4, 5, 10);

g.addEdge(5, 6, 2);

g.addEdge(6, 7, 1);

g.addEdge(6, 8, 6);

g.addEdge(7, 8, 7);

clock_t start,end;

start=clock();

cout << "Edges of MST are \n";

int mst_wt = g.kruskalMST();

cout << "\nWeight of MST is " << mst_wt;

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken: "<<duration*1e6<<" microseconds"<< endl;

return 0;

OUTPUT:
b) Prim’s Algorithm.

#include<iostream>

using namespace std;

// Number of vertices in the graph

const int V=5;

// Function to find the vertex with minimum key value

int min_Key(int key[], bool visited[])

int min = 999, min_index; // 999 represents an Infinite value

for (int v = 0; v < V; v++) {

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

// vertex should not be visited

min = key[v];

min_index = v;

return min_index;

// Function to print the final MST stored in parent[]

int print_MST(int parent[], int cost[V][V])

int minCost=0;

cout<<"\nEdge \tWeight\n";

for (int i = 1; i< V; i++) {

cout<<parent[i]<<" - "<<i<<" \t"<<cost[i][parent[i]]<<" \n";

minCost+=cost[i][parent[i]];

cout<<"\nTotal cost is : "<<minCost;


return 0;

// Function to find the MST using adjacency cost matrix representation

void find_MST(int cost[V][V])

int parent[V], key[V];

bool visited[V];

// Initialize all the arrays

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

key[i] = 999; // 99 represents an Infinite value

visited[i] = false;

parent[i]=-1;

key[0] = 0; // Include first vertex in MST by setting its key vaue to 0.

parent[0] = -1; // First node is always root of MST

// The MST will have maximum V-1 vertices

for (int x = 0; x < V - 1; x++)

// Finding the minimum key vertex from the

//set of vertices not yet included in MST

int u = min_Key(key, visited);

visited[u] = true; // Add the minimum key vertex to the MST

// Update key and parent arrays

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

{ // cost[u][v] is non zero only for adjacent vertices of u

// visited[v] is false for vertices not yet included in MST


// key[] gets updated only if cost[u][v] is smaller than key[v]

if (cost[u][v]!=0 && visited[v] == false && cost[u][v] < key[v])

parent[v] = u;

key[v] = cost[u][v];

// print the final MST

print_MST(parent, cost);

int main()

cout<<"Name : AMAN CHAUHAN\nRoll no.: 14614802719\nGroup : 5C7\n\n";

cout<<"PRIM's ALGORITHM:\n\n";

int cost[V][V];

cout<<"Enter the vertices for a graph with "<<V<< " vetices : "<<endl;

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

for(int j=0;j<V;j++)

cin>>cost[i][j];

clock_t start,end;

start=clock();
find_MST(cost);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime Taken: "<<duration*1e6<<" microseconds"<< endl;

return 0;

OUTPUT:
VIVA – QUESTIONS

Ans) A greedy algorithm is an algorithmic strategy that makes the best optimal choice at each small
stage with the goal of this eventually leading to a globally optimum solution. This means that the
algorithm picks the best solution at the moment without regard for consequences.

Ans) Kruskal's Algorithm is a famous greedy algorithm. It is used for finding the Minimum Spanning
Tree (MST) of a given graph. To apply Kruskal's algorithm, the given graph must be weighted,
connected and undirected.

Ans) Prim's Algorithm is used to find the minimum spanning tree from a graph. Prim's algorithm finds
the subset of edges that includes every vertex of the graph such that the sum of the weights of the edges
can be minimized.

Ans) The time complexity of the Kruskal's Algorithm is O ( E l o g V ).

The time complexity of the Prim's Algorithm is O ( ( V + E ) l o g V ).

Ans) Prim's Algorithm grows a solution from a random vertex by adding the next cheapest vertex to the
existing tree.

Kruskal's Algorithm grows a solution from the cheapest edge by adding the next cheapest edge to the
existing tree / forest.
Date: 14/12/21 EXPERIMENT- 8

Aim: a) To implement Naïve String Matching Algorithm.


b) To implement Rabin Karp String Matching Algorithm.

c) To implement Knuth Morris Pratt Algorithm.

SOURCE CODE:
a) Naïve String Matching Algorithm.

#include<iostream>

#include<string.h>

using namespace std;

void search(char *pat, char *txt)

int M = strlen(pat);

int N = strlen(txt);

/* A loop to slide pat[] one by one */

for (int i = 0; i <= N - M; i++)

int j;

for (j = 0; j < M; j++){ /* For current index i, check for pattern match */

if (txt[i + j] != pat[j])

break;

if (j == M) // if pat[0...M-1] = txt[i, i+1, ...i+M-1]

printf("Pattern found at index %d \n", i);

int main()
{

cout<<"Name : AMAN CHAUHAN\nRoll no.: 14614802719\nGroup : 5C7\n\n";

cout<<"Naive String Matching Algorithm\n\n";

char *txt = "AABAACAADAABAAABAA";

char *pat = "AABA";

clock_t start,end;

start=clock();

search(pat, txt);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime : "<<duration*1e6<<" microseconds"<< endl;

return 0;

OUTPUT:
b) Rabin Karp String Matching Algorithm.

#include <iostream>

#include <string.h>

using namespace std;

#define d 10

void rabinKarp(char pattern[], char text[], int q) {

int m = strlen(pattern);

int n = strlen(text);

int i, j;

int p,t = 0;

int h = 1;

for (i = 0; i < m - 1; i++)

h = (h * d) % q;

for (i = 0; i < m; i++) { // Calculate hash value for pattern and text

p = (d * p + pattern[i]) % q;

t = (d * t + text[i]) % q;

// Find the match

for (i = 0; i <= n - m; i++) {

if (p == t) {

for (j = 0; j < m; j++) {

if (text[i + j] != pattern[j])

break;

if (j == m)

cout << "Pattern is found at position: " << i + 1 << endl;

if (i < n - m) {
t = (d * (t - text[i] * h) + text[i + m]) % q;

if (t < 0)

t = (t + q);

int main()

cout<<"Name : AMAN CHAUHAN\nRoll no.: 14614802719\nGroup : 5C7\n\n";

cout<<"Rabin Karp Algorithm\n\n";

char text[] = "ABCCDDAEFGCDD";

char pattern[] = "CDD";

int q = 13;

clock_t start,end;

start=clock();

rabinKarp(pattern, text, q);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime : "<<duration*1e6<<" microseconds"<< endl;

return 0;

OUTPUT:
c) Knuth Morris Pratt Algorithm.

#include <bits/stdc++.h>

using namespace std;

void computeLPSArray(char* pat, int M, int* lps);

// Prints occurrences of txt[] in pat[]

void KMPSearch(char* pat, char* txt)

int M = strlen(pat);

int N = strlen(txt);

// create lps[] that will hold the longest prefix suffix values for pattern

int lps[M];

// Preprocess the pattern (calculate lps[] array)

computeLPSArray(pat, M, lps);

int i = 0; // index for txt[]

int j = 0; // index for pat[]

while (i < N) {

if (pat[j] == txt[i]) {

j++;

i++;

if (j == M) {

printf("Found pattern at index %d ", i - j);

j = lps[j - 1];

// mismatch after j matches

else if (i < N && pat[j] != txt[i]) {

// Do not match lps[0..lps[j-1]] characters,they will match anyway


if (j != 0)

j = lps[j - 1];

else

i = i + 1;

// Fills lps[] for given patttern pat[0..M-1]

void computeLPSArray(char* pat, int M, int* lps)

{ // length of the previous longest prefix suffix

int len = 0;

lps[0] = 0; // lps[0] is always 0

// the loop calculates lps[i] for i = 1 to M-1

int i = 1;

while (i < M) {

if (pat[i] == pat[len]) {

len++;

lps[i] = len;

i++;

else // (pat[i] != pat[len])

if (len != 0) {

len = lps[len - 1];

else // if (len == 0)

lps[i] = 0;

i++;
}

int main()

cout<<"Name : AMAN CHAUHAN\nRoll no.: 14614802719\nGroup : 5C7\n\n";

cout<<"KMP Algorithm Algorithm\n\n";

char txt[] = "ABABDABACDABABCABAB";

char pat[] = "ABABCABAB";

clock_t start,end;

start=clock();

KMPSearch(pat, txt);

end=clock();

double duration=double(end-start)/double(CLOCKS_PER_SEC);

cout <<"\n\nTime : "<<duration*1e6<<" microseconds"<< endl;

return 0;

OUTPUT:
VIVA – QUESTIONS

Ans) String-matching algorithms, are an important class of string algorithms that try to find a place
where one or several strings are found within a larger string or text.

Ans) Naive Algorithm: It slides the pattern over text one by one and check for a match. If a match is
found, then slides by 1 again to check for subsequent matches.

Ans) Rabin Karp Algorithm: It matches the hash value of the pattern with the hash value of current
substring of text, and if the hash values match then only it starts matching individual characters.

Ans) KMP (Knuth Morris Pratt) Algorithm: The idea is whenever a mismatch is detected, we already
know some of the characters in the text of the next window. So, we take advantage of this information to
avoid matching the characters that we know will anyway match.

Ans) The time complexity of Naïve Pattern Search method is O(m*n). The m is the size of pattern and n
is the size of the main string.

The average and best-case running time of the Rabin-Karp algorithm is O(n+m), but its worst-case time
is O(nm).

The time complexity of KMP algorithm is O(n) in the worst case.

You might also like