You are on page 1of 58

PROGRAM-1(a)

Aim: To implement linear search using array as a data structure and analyze its time
complexity

Algorithm:

The steps used in the implementation of Linear Search are listed as follows -

1. First, we have to traverse the array elements using a for loop.


2. In each iteration of for loop, compare the search element with the current array
element, and -
o If the element matches, then print the position of the corresponding array
element.
o If the element does not match, then move to the next element.
3. If there is no match or the search element is not present in the given array, then print
number not found.

Source Code:
#include <iostream>
#include <stdlib.h>
using namespace std;
#include <time.h>
#include <chrono>

void linarSearch(int arr[], int n, int num)


{
auto start = chrono::high_resolution_clock::now();
int i,c=0,pos;
for (i = 0; i < n; i++)
{
if (arr[i] == num)
{
c=1;
pos=i+1;
break;
}
}

if(c==0)
cout << "Number not found !!"<< endl;
else
cout << "Number found at position:"<< " " << pos<< endl;

auto finish = chrono::high_resolution_clock::now();

cout << "\nTime taken:" << chrono::duration_cast<chrono::nanoseconds>(finish -


start).count() << " ns" << endl;
}

int main()
{
int num, n, i, m;
cout << "Enter the array size: ";
cin >> n;
int a[n], b[n], c[n];

// BEST CASE
for (i = 0; i < n; i++)
{
a[i] = i;
}
// AVERAGE CASE
for(int i=0;i<n;i++)
{
m=rand()%n;
if(m!=0)
b[i]=m;
}
// WORST CASE
for(int i=0;i<n;i++)
{
c[i]=n-1;
}

cout << "Enter the number to be searched: ";


cin >> num;

cout<<"Best Case"<<endl;
linarSearch(a,n,num);

cout<<"Average Case"<<endl;
linarSearch(b,n,num);

cout<<"Worst Case"<<endl;
linarSearch(c,n,num);

return 0;
}
Output:

Time complexity:
Best Case: O(1)
Average Case: O(n)
Worst Case: O(n)
PROGRAM-1(b)

Aim: To implement Binary search using array as a data structure and analyze its time
complexity

Algorithm:

The steps used in the implementation of Binary Search are listed as follows –

1. Binary search follows the divide and conquer approach in which the list is divided
into two halves.

2. The item is compared with the middle element of the list.

3. If the match is found then, the location of the middle element is printed.

4. Otherwise, we search into either of the halves depending upon the result produced
through the match.

5. If there is no match or the search element is not present in the given array, then print
number not found.

Source Code:
#include <iostream>
#include <stdlib.h>
using namespace std;
#include <time.h>
#include <chrono>

void BinarySearch(int arr[], int n, int num)


{
auto start = chrono::high_resolution_clock::now();

int first = 0, last = n - 1, middle = (first + last) / 2;

while (first <= last)


{
if (arr[middle < num])
{
first = middle + 1;
}
else if (arr[middle] == num)
{
cout << num << " "
<< "Found at location -"<< middle + 1 << endl;
break;
}
else
{
last = middle - 1;
}
middle = (first + last) / 2;

if (first > last)


{
cout << "Not found!!"<< " " << num << " is not present in the list:" << endl;
}
}

auto finish = chrono::high_resolution_clock::now();

cout << "\nTime taken:" << chrono::duration_cast<chrono::nanoseconds>(finish -


start).count() << " ns" << endl;
}

int main()
{
int num, n, i, m;
cout << "Enter the array size:";
cin >> n;
int a[n], b[n], c[n];

for (i=0;i<n;i++)
{
a[i]=i;
}

cout << "Enter the number to be searched:";


cin >> num;

BinarySearch(a, n, num);

return 0;
}

Output:
TIME COMPLEXITY:

Best Case: O(1)


Average Case: O(logn)
Worst Case: O(logn)
PROGRAM-2(a)

Aim: To implement insertion sort using array as a data structure and analyze its time
complexity.

Algorithm:
Following are the steps of implementation:
1. If it is the first element, it is already sorted, return 1.
2. Pick next element.
3. Compare with all elements in the sorted sub-list.
4. Shift all the elements in the sorted sub-list that is greater than the value to be sorted.
5. Insert the value.
6. Repeat until list is sorted.

Source Code:
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <chrono>
using namespace std;

void InsertionSort(int arr[], int n) {


    auto start = chrono::high_resolution_clock::now();
  
    int i, key, j;
    for (i = 1; i < n; i++)
  {
        key = arr[i];
        j = i - 1;
    
        while (j >= 0 && arr[j] > key)
    {
            arr[j + 1] = arr[j];
            j = j - 1;
    }
        arr[j + 1] = key;
  }
  
    auto finish = chrono::high_resolution_clock::now();
    cout << "Time taken: " << chrono::duration_cast<chrono::nanoseconds> (finish -
start).count() << "ns" << endl;
}

int main() {
    int n,i,m;
    cout << "Enter the size of array: ";
    cin >> n;
    int a[n], b[n], c[n];
  
    for (i = 0; i < n; i++){
        a[i] = i;
  }
    for (i = 0; i < n; i++){
        m = rand() % n;
        if (m != 0){
            b[i] = m;
    }
  }
    for (i = 0; i < n; i++){
        c[i] = n - i - 1;
  }
  
    cout << "Worst Case: \n";
    InsertionSort(c,n);
  
    cout << "Average Case: \n";
    InsertionSort(b,n);
  
    cout << "Best Case: \n";
    InsertionSort(a,n);
}

Output:

Time complexity:
Best Case: O(n)
Average case: O(n^2)
Worst Case: O(n^2)
PROGRAM-2(b)

Aim: To implement insertion sort using array as a data structure and analyze its time
complexity.

Algorithm:
1. Traverse the given array.
2. Compare the element and the next element.
3. If the current element is greater than the next element, then swap both the elements.

Source Code:
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <chrono>
using namespace std;

void BubbleSort(int arr[], int n) {


    auto start = chrono::high_resolution_clock::now();
  
    int i, j;
    for (i = 0; i < n - 1; i++){
        for (j = 0; j < n - i - 1; j++){
            if (arr[j] > arr[j + 1]){
                swap(arr[j], arr[j + 1]);
      }
    }
  }
  
    auto finish = chrono::high_resolution_clock::now();
    cout << "Time taken: " << chrono::duration_cast<chrono::nanoseconds> (finish -
start).count() << "ns" << endl;
}

int main() {
    int n,i,m;
    cout << "Enter the size of array: ";
    cin >> n;
    int a[n], b[n], c[n];
  
    for (i = 0; i < n; i++){
        a[i] = i;
  }
    for (i = 0; i < n; i++){
        m = rand() % n;
        if (m != 0){
            b[i] = m;
    }
  }
    for (i = 0; i < n; i++){
        c[i] = n - i - 1;
  }
  
    cout << "Worst Case: \n";
    BubbleSort(c,n);
  
    cout << "Average Case: \n";
    BubbleSort(b,n);
  
    cout << "Best Case: \n";
    BubbleSort(a,n);
}

Output:

Time Complexity:

Best Case : O(n)


Average Case : O(n^2)
Worst Case : O(n^2)
PROGRAM-2(c)

Aim: To implement selection sort using array as a data structure and analyze its time
complexity.

Algorithm:
1. Set MIN to location 0.
2. Search the minimum element in the list.
3. Swap the value at location MIN.
4. Increment MIN to point to next element.
5. Repeat until list is sorted.

Source Code:

#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <chrono>
using namespace std;

void swap(int &a, int &b) {


   int temp;
   temp = a;
   a = b;
   b = temp;
}

void SelectionSort(int arr[], int n) {


    auto start = chrono::high_resolution_clock::now();
  
    int i, j, imin;
    for(i = 0; i< n-1; i++) {
        imin = i;
        for(j = i+1; j < n ; j++){
            if(arr[j] < arr[imin]){
                imin = j;
      }
    }  
        swap(arr[i], arr[imin]);
  }
  
    auto finish = chrono::high_resolution_clock::now();
    cout << "Time taken: " << chrono::duration_cast<chrono::nanoseconds> (finish -
start).count() << "ns" << endl;
}

void swapping(int &a, int &b) {


   int temp;
   temp = a;
   a = b;
   b = temp;
}

int main() {
    int n,i,m;
    cout << "Enter the size of array: ";
    cin >> n;
    int a[n], b[n], c[n];
  
    for (i = 0; i < n; i++){
        a[i] = i;
  }
    for (i = 0; i < n; i++){
        m = rand() % n;
        if (m != 0){
            b[i] = m;
    }
  }
    for (i = 0; i < n; i++){
        c[i] = n - i - 1;
  }
  
    cout << "Worst Case: \n";
    SelectionSort(c,n);
  
    cout << "Average Case: \n";
    SelectionSort(b,n);
  
    cout << "Best Case: \n";
    SelectionSort(a,n);
}
Output:

Time Complexity:

Best Case : O(n^2)


Average Case : O(n^2)
Worst Case : O(n^2)
PROGRAM-2(d)

Aim: To implement merge sort using array as a data structure and analyze its time
complexity.

Algorithm:
MergeSort(arr[], 1, r)
If r>1
1. Find the middle point to divide the array into two halves:
Middle m = (1+r)/2
2. Call mergeSort for first half:
Call mergeSort(arr, 1, m)
3. Call mergeSort for second half:
Call mergeSort(arr, m+1, r)
4. Merge the two halves sorted in step 2 and 3:
Call merge(arr, 1, m, r)

Source code:
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <chrono>
using namespace std;

void merge(int arr[], int p, int q, int r) {


    int n1 = q - p + 1;
    int n2 = r - q;

    int L[n1], M[n2];

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


        L[i] = arr[p + i];
    for (int j = 0; j < n2; j++)
        M[j] = arr[q + 1 + j];

    int i, j, k;
    i = 0;
    j = 0;
    k = p;

    while (i < n1 && j < n2) {


        if (L[i] <= M[j]) {
            arr[k] = L[i];
            i++;
        } else {
            arr[k] = M[j];
            j++;
    }
        k++;
  }

    while (i < n1) {


        arr[k] = L[i];
        i++;
        k++;
  }

    while (j < n2) {


        arr[k] = M[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 Driver(int arr[], int l, int r){


    auto start = chrono::high_resolution_clock::now();
    MergeSort(arr, 0, r);
    auto finish = chrono::high_resolution_clock::now();
    cout << "Time taken: " << chrono::duration_cast<chrono::nanoseconds> (finish -
start).count() << "ns" << endl;
}

int main() {
    int n,i,m;
    cout << "Enter the size of array: ";
    cin >> n;
    int a[n], b[n], c[n];
  
    for (i = 0; i < n; i++){
        a[i] = i;
  }
    for (i = 0; i < n; i++){
        m = rand() % n;
        if (m != 0){
            b[i] = m;
    }
  }
    for (i = 0; i < n; i++){
        c[i] = n - i - 1;
  }
  
    cout << "Worst Case: \n";
    Driver(c,0,n);
  
    cout << "Average Case: \n";
    Driver(b,0,n);
  
    cout << "Best Case: \n";
    Driver(a,0,n);
}

Output:

Time complexity:
Best Case : O(nlogn)
Average Case : O(nlogn)
Worst Case : O(nlogn)
PROGRAM-3(a)

Aim: To implement quick sort using array as a data structure and analyze its time
complexity.

Algorithm:
1. Choose the highest index value has pivot.
2. Take two variables to point left and right of the list excluding pivot.
3. Left points to the low index.
4. Right points to the high.
5. While value at left is less than pivot move right.
6. While value at right is greater than pivot move left.
7. If both step 5 and 6 does not match swap left and right.
8. If left >= right, the point where they meet is new pivot.

Source Code:

Output:

Time complexity:
Best case : O(nlogn)
Average case : O(nlogn)
Worst case : O(n^2)
PROGRAM-3(b)

Aim: To implement radix sort using array as a data structure and analyze its time
complexity.

Algorithm:
1. Take input of data.
2. Get the maximum of input data.
3. Run the countSort() till (m/exp)>0.
4. Sort the data on the basis of the digit at the (exp)th place.
5. Assign the sorted data back to arr[] array.
6. Check the condition in step 3.
7. If false, print the sorted output.
8. Exit.

Source Code:
#include<iostream>
using namespace std;
#include<stdlib.h>
#include<time.h>
#include<chrono>

void countSort(int arr[], int n, int exp)


{
    int output[n];
    int i, count[10] = { 0 };

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


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

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


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

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


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

int getMax(int arr[], int n)


{
    int mx = arr[0];
    for (int i = 1; i < n; i++)
        if (arr[i] > mx)
            mx = arr[i];
    return mx;
}
void radixsort(int n,int arr[])
{
   auto start=chrono::high_resolution_clock::now();
    int m = getMax(arr, n);
 
    for (int exp = 1; m / exp > 0; exp *= 10)
        countSort(arr, n, exp);
  
    auto finish=chrono::high_resolution_clock::now();

    cout<<"Time taken:"<<chrono::duration_cast<chrono::nanoseconds>(finish-
start).count()<<"ns."<<endl;
}
int main()
{
int num, n, i, m;
cout<<"Enter the array size:";
cin>>n;
int a[n], b[n], c[n];

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


{
a[i] = i;
}

for(int i=0;i<n;i++)
{
m=rand()%n;
if(m!=0)
b[i]=m;
}
for(int i=0;i<n;i++)
{
c[i]=n-i-1;
}
cout<<"Best Case"<<endl;
radixsort(n,a);
cout<<"Average Case"<<endl;
radixsort(n,b);
cout<<"Worst Case"<<endl;
radixsort(n,c);
return 0;
}

Output:
Time Complexity:
Best case: O(nk)
Average case: O(nk)
Worst case: O(nk)
PROGRAM-3(c)

Aim: To implement Strassen’s matrix multiplication and analyse its time complexity.

Algorithm:
Matmul(A, B, C , n)
1. If n = 1, then //best case
2. C = C + A*B
3. Else
4. Matmul(A, B, C , n/4)
5. Matmul(A, B + (n/4), C+(n/4) , n/4)
6. Matmul(A + 2*(n/4), B, C + 2*(n/4) , n/4)
7. Matmul(A + 2*(n/4), B + (n/4), C + 3*(n/4), n/4)
8. Matmul(A + (n/4), B + 2*(n/4), C , n/4)
9. Matmul(A + (n/4), B + 3*(n/4), C + (n/4), n/4)
10. Matmul(A + 3*(n/4), B + 2*(n/4), C + 2*(n/4) , n/4)
11. Matmul(A + 3*(n/4), B + 3*(n/4), C + 3*(n/4), n/4)
12. End

Source Code:
#include <bits/stdc++.h>
using namespace std;
 
#define ROW_1 4
#define COL_1 4
 
#define ROW_2 4
#define COL_2 4
auto start=chrono::high_resolution_clock::now();
 
void add_matrix(vector<vector<int> > matrix_A,
                vector<vector<int> > matrix_B,
                vector<vector<int> >& matrix_C,
                int split_index)
{
    for (auto i = 0; i < split_index; i++)
        for (auto j = 0; j < split_index; j++)
            matrix_C[i][j]
                = matrix_A[i][j] + matrix_B[i][j];
}
 
vector<vector<int> >multiply_matrix(vector<vector<int> > matrix_A,
                vector<vector<int> > matrix_B)
{
    int col_1 = matrix_A[0].size();
    int row_1 = matrix_A.size();
    int col_2 = matrix_B[0].size();
    int row_2 = matrix_B.size();
 
    if (col_1 != row_2) {
        cout << "\nError: The number of columns in Matrix "
                "A  must be equal to the number of rows in "
                "Matrix B\n";
        return {};
  }
 
    vector<int> result_matrix_row(col_2, 0);
    vector<vector<int> > result_matrix(row_1,
                                       result_matrix_row);
 
    if (col_1 == 1)
        result_matrix[0][0]
            = matrix_A[0][0] * matrix_B[0][0];
    else {
        int split_index = col_1 / 2;
 
        vector<int> row_vector(split_index, 0);
        vector<vector<int> > result_matrix_00(split_index,
                                              row_vector);
        vector<vector<int> > result_matrix_01(split_index,
                                              row_vector);
        vector<vector<int> > result_matrix_10(split_index,
                                              row_vector);
        vector<vector<int> > result_matrix_11(split_index,
                                              row_vector);
 
        vector<vector<int> > a00(split_index, row_vector);
        vector<vector<int> > a01(split_index, row_vector);
        vector<vector<int> > a10(split_index, row_vector);
        vector<vector<int> > a11(split_index, row_vector);
        vector<vector<int> > b00(split_index, row_vector);
        vector<vector<int> > b01(split_index, row_vector);
        vector<vector<int> > b10(split_index, row_vector);
        vector<vector<int> > b11(split_index, row_vector);
 
        for (auto i = 0; i < split_index; i++)
            for (auto j = 0; j < split_index; j++) {
                a00[i][j] = matrix_A[i][j];
                a01[i][j] = matrix_A[i][j + split_index];
                a10[i][j] = matrix_A[split_index + i][j];
                a11[i][j] = matrix_A[i + split_index]
                                    [j + split_index];
                b00[i][j] = matrix_B[i][j];
                b01[i][j] = matrix_B[i][j + split_index];
                b10[i][j] = matrix_B[split_index + i][j];
                b11[i][j] = matrix_B[i + split_index]
                                    [j + split_index];
      }
 
        add_matrix(multiply_matrix(a00, b00),
                   multiply_matrix(a01, b10),
                   result_matrix_00, split_index);
        add_matrix(multiply_matrix(a00, b01),
                   multiply_matrix(a01, b11),
                   result_matrix_01, split_index);
        add_matrix(multiply_matrix(a10, b00),
                   multiply_matrix(a11, b10),
                   result_matrix_10, split_index);
        add_matrix(multiply_matrix(a10, b01),
                   multiply_matrix(a11, b11),
                   result_matrix_11, split_index);
 
        for (auto i = 0; i < split_index; i++)
            for (auto j = 0; j < split_index; j++) {
                result_matrix[i][j]
                    = result_matrix_00[i][j];
                result_matrix[i][j + split_index]
                    = result_matrix_01[i][j];
                result_matrix[split_index + i][j]
                    = result_matrix_10[i][j];
                result_matrix[i + split_index]
                             [j + split_index]
                    = result_matrix_11[i][j];
      }
 
        result_matrix_00.clear();
        result_matrix_01.clear();
        result_matrix_10.clear();
        result_matrix_11.clear();
        a00.clear();
        a01.clear();
        a10.clear();
        a11.clear();
        b00.clear();
        b01.clear();
        b10.clear();
        b11.clear();
  }
    return result_matrix;
}
 
int main()
{
    vector<vector<int> > matrix_A = { { 1, 1, 1, 1 },
                                      { 2, 2, 2, 2 },
                                      { 3, 3, 3, 3 },
                                      { 2, 2, 2, 2 } };
 
 
    vector<vector<int> > matrix_B = { { 1, 1, 1, 1 },
                                      { 2, 2, 2, 2 },
                                      { 3, 3, 3, 3 },
                                      { 2, 2, 2, 2 } };
 
 
    vector<vector<int> > result_matrix(
        multiply_matrix(matrix_A, matrix_B));
   auto finish=chrono::high_resolution_clock::now();

    cout<<"Time taken:"<<chrono::duration_cast<chrono::nanoseconds>(finish-
start).count()<<"ns."<<endl;
  
}

Output:

Experiment 5
Aim: To implement Knapsack and analyze its time complexity.
Algorithm
The maximum value obtained from ‘N’ items is the max of the following two values. 
 Maximum value obtained by N-1 items and W weight (excluding nth item)
 Value of nth item plus maximum value obtained by N-1 items and W
minus the weight of the Nth item (including Nth item)
 If the weight of the ‘Nth’ item is greater than ‘W’, then the Nth item cannot
be included and case 1 is the only possibility.

Program
#include <bits/stdc++.h>
#include<time.h>
#include<chrono>
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]);
auto start=chrono::high_resolution_clock::now();
cout << knapSack(W, wt, val, n);
auto finish=chrono::high_resolution_clock::now();
cout<<"\nTime Taken:"<<chrono::duration_cast<chrono::nanoseconds>(finish-
start).count()<<"ns"<<endl;
return 0;
}
Output
Experiment 6
AIM: To implement longest common subsequence problem and analyze its time complexity.
Algorithm:
Let the input sequences be X[0..m-1] and Y[0..n-1] of lengths m and n respectively.
And let L(X[0..m-1], Y[0..n-1]) be the length of LCS of the two sequences X and Y.
Following is the recursive definition of L(X[0..m-1], Y[0..n-1]).
If last characters of both sequences match (or X[m-1] == Y[n-1]) then 
L(X[0..m-1], Y[0..n-1]) = 1 + L(X[0..m-2], Y[0..n-2])
If last characters of both sequences do not match (or X[m-1] != Y[n-1]) then 
L(X[0..m-1], Y[0..n-1]) = MAX ( L(X[0..m-2], Y[0..n-1]), L(X[0..m-1], Y[0..n-2]) )

Code:
#include <iostream>
#include<time.h>
#include<chrono>
#include <string.h>
using namespace std;

int LCSubStr(char* X, char* Y, int m, int n)


{

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


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

if (i == 0 || j == 0)
LCSuff[i][j] = 0;

else if (X[i - 1] == Y[j - 1]) {


LCSuff[i][j] = LCSuff[i - 1][j - 1] + 1;
result = max(result, LCSuff[i][j]);
}
else
LCSuff[i][j] = 0;
}
}
return result;
}

int main()
{
char X[] = "OldSite:GeeksforGeeks.org";
char Y[] = "NewSite:GeeksQuiz.com";

int m = strlen(X);
int n = strlen(Y);
auto start=chrono::high_resolution_clock::now();
cout << "Length of Longest Common Substring is "
<< LCSubStr(X, Y, m, n);
auto finish=chrono::high_resolution_clock::now();
cout<<"\nTime Taken:"<<chrono::duration_cast<chrono::nanoseconds>(finish-
start).count()<<"ns"<<endl;
return 0;
}

Output
Experiment 7
Aim: To implement Dijkstra’s Algorithm and analyze its time complexity.
Algorithm: 1. Create a set sptSet (shortest path tree set) that keeps track of vertices included in
shortest path tree, i.e., whose minimum distance from source is calculated and finalized. Initially,
this set is empty.

2. Assign a distance value to all vertices in the input graph. Initialize all distance values as INFINITE.
Assign distance value as 0 for the source vertex so that it is picked first.

3. While sptSet doesn’t include all vertices a. Pick a vertex u which is not there in sptSet and has
minimum distance value. b. Include u to sptSet. c. Update distance value of all adjacent vertices of u.
To update the distance values, iterate through all adjacent vertices. For every adjacent vertex v, if
sum of distance value of u (from source) and weight of edge u-v, is less than the distance value of v,
then update the distance value of v.

Code
#include <iostream>
#include<time.h>
#include<chrono>
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 } };
auto start=chrono::high_resolution_clock::now();
dijkstra(graph, 0);
auto finish=chrono::high_resolution_clock::now();
cout<<"\nTime Taken:"<<chrono::duration_cast<chrono::nanoseconds>(finish-
start).count()<<"ns"<<endl; return 0;
}

Output:

Experiment 8
Aim: To implement optimal binary search tree problem and analyze its time complexity.

Algorithm:
e[1…n + 1, 0…n],

w[1…n + 1, 0…n],

root[1…n + 1, 0…n]

for i = 1 to n + 1

do e[i, i - 1] := qi - 1 w[i, i - 1] := qi - 1

for l = 1 to n

do

for i = 1 to n – l + 1
do j = i + l – 1 e[i, j] := ∞

w[i, i] := w[i, i -1] + pj + qj

for r = i to j

do t := e[i, r - 1] + e[r + 1, j] + w[i, j]


if t < e[i, j] e[i, j] := t root[i, j] := r

return e and root

Code
#include <bits/stdc++.h>

#include<time.h>

#include<chrono>

using namespace std;

int sum(int freq[], int i, int j);

int optCost(int freq[], int i, int j)

{ if (j < i)

return 0;

if (j == i)

return freq[i];

int fsum = sum(freq, i, j);

int min = INT_MAX;

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

int cost = optCost(freq, i, r - 1) +

optCost(freq, r + 1, j);

if (cost < min)

min = cost;

return min + fsum;

}
int optimalSearchTree(int keys[],int freq[], int n)

return optCost(freq, 0, n - 1);

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

int s = 0;

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

s += freq[k];

return s;

int main()

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

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

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

auto start=chrono::high_resolution_clock::now();

cout << "Cost of Optimal BST is "

<< optimalSearchTree(keys, freq, n);

auto finish=chrono::high_resolution_clock::now();

cout<<"\nTime Taken:"<<chrono::duration_cast<chrono::nanoseconds>(finish-
start).count()<<"ns"<<endl;

return 0;

OUTPUT
Experiment 9

AIM: To implement Bellman Ford Algorithm and analyze its time complexity.
Algorithm:
Input: Graph and a source vertex src Output: Shortest distance to all vertices from src. If there is a
negative weight cycle, then shortest distances are not calculated, negative weight cycle is reported.
1. This step initializes distances from the source to all vertices as infinite and distance to the source
itself as 0. Create an array dist[] of size |V| with all values as infinite except dist[src] where src is
source vertex.

2. This step calculates shortest distances. Do following |V|-1 times where |V| is the number of
vertices in given graph. Do following for each edge u-v i. dist[v] > dist[u] + weight of edge uv, then
update dist[v] ii. dist[v] = dist[u] + weight of edge uv

3. This step reports if there is a negative weight cycle in graph. Do following for each edge u-v ……If
dist[v] > dist[u] + weight of edge uv, then “Graph contains negative weight cycle” The idea of step 3
is, step 2 guarantees the shortest distances if the graph doesn’t contain a negative weight cycle. If
we iterate through all edges one more time and get a shorter path for any vertex, then there is a
negative weight cycle

CODE
#include <bits/stdc++.h>
#include<time.h>
#include<chrono>
using namespace std;

struct Edge {
int src, dest, weight;
};
struct Graph {
// V-> Number of vertices, E-> Number of edges
int V, E;

// graph is represented as an array of edges.


struct Edge* edge;
};

struct Graph* createGraph(int V, int E)


{
struct Graph* graph = new Graph;
graph->V = V;
graph->E = E;
graph->edge = new Edge[E];
return graph;
}
void printArr(int dist[], int n)
{
printf("Vertex Distance from Source\n");
for (int i = 0; i < n; ++i)
printf("%d \t\t %d\n", i, dist[i]);
}

void BellmanFord(struct Graph* graph, int src)


{
int V = graph->V;
int E = graph->E;
int dist[V];
for (int i = 0; i < V; i++)
dist[i] = INT_MAX;
dist[src] = 0;
for (int i = 1; i <= V - 1; i++) {
for (int j = 0; j < E; j++) {
int u = graph->edge[j].src;
int v = graph->edge[j].dest;
int weight = graph->edge[j].weight;
if (dist[u] != INT_MAX
&& dist[u] + weight < dist[v])
dist[v] = dist[u] + weight;
}
}
for (int i = 0; i < E; i++) {
int u = graph->edge[i].src;
int v = graph->edge[i].dest;
int weight = graph->edge[i].weight;
if (dist[u] != INT_MAX
&& dist[u] + weight < dist[v]) {
printf("Graph contains negative weight cycle");
return;

}
}

printArr(dist, V);

return;
}

int main()
{
int V = 5;
int E = 8;
struct Graph* graph = createGraph(V, E);

graph->edge[0].src = 0;
graph->edge[0].dest = 1;
graph->edge[0].weight = -1;

graph->edge[1].src = 0;
graph->edge[1].dest = 2;
graph->edge[1].weight = 4;

graph->edge[2].src = 1;
graph->edge[2].dest = 2;
graph->edge[2].weight = 3;

graph->edge[3].src = 1;
graph->edge[3].dest = 3;
graph->edge[3].weight = 2;

graph->edge[4].src = 1;
graph->edge[4].dest = 4;
graph->edge[4].weight = 2;

graph->edge[5].src = 3;
graph->edge[5].dest = 2;
graph->edge[5].weight = 5;

graph->edge[6].src = 3;
graph->edge[6].dest = 1;
graph->edge[6].weight = 1;

graph->edge[7].src = 4;
graph->edge[7].dest = 3;
graph->edge[7].weight = -3;

auto start=chrono::high_resolution_clock::now();
BellmanFord(graph, 0);
auto finish=chrono::high_resolution_clock::now();
cout<<"\nTime Taken:"<<chrono::duration_cast<chrono::nanoseconds>(finish-
start).count()<<"ns"<<endl;

return 0;
}
Output

Experiment 10
AIM: To implement Huffman Coding and analyze its time complexity.

Algorithm:
1. Create a leaf node for each unique character and build a min heap of all leaf nodes.

2. Extract two nodes with the minimum frequency from the min heap.
3. Create a new internal node with a frequency equal to the sum of the two nodes frequencies.
Make the first extracted node as its left child and the other extracted node as its right child. Add this
node to the min heap.

4. Repeat steps 2 and 3 until the heap contains only one node. The remaining node is the root node
and the tree is complete

CODE
#include <iostream>
#include <cstdlib>
#include<time.h>
#include<chrono>
using namespace std;

#define MAX_TREE_HT 100


struct MinHeapNode {
char data;
unsigned freq;
struct MinHeapNode *left, *right;
};

struct MinHeap {
unsigned size;
unsigned capacity;
struct MinHeapNode** array;
};

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

struct MinHeap* createMinHeap(unsigned capacity)

struct MinHeap* minHeap


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

minHeap->size = 0;

minHeap->capacity = capacity;

minHeap->array
= (struct MinHeapNode**)malloc(minHeap->
capacity * sizeof(struct MinHeapNode*));
return minHeap;
}

void swapMinHeapNode(struct MinHeapNode** a,


struct MinHeapNode** b)

{
struct MinHeapNode* t = *a;
*a = *b;
*b = t;
}

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);
}
}
int isSizeOne(struct MinHeap* minHeap)
{

return (minHeap->size == 1);


}

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

void buildMinHeap(struct MinHeap* minHeap)

int n = minHeap->size - 1;
int i;

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


minHeapify(minHeap, i);
}
void printArr(int arr[], int n)
{
int i;
for (i = 0; i < n; ++i)
cout<< arr[i];

cout<<"\n";
}

int isLeaf(struct MinHeapNode* root)

{
return !(root->left) && !(root->right);
}
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;
}
struct MinHeapNode* buildHuffmanTree(char data[], int freq[], int size)

{
struct MinHeapNode *left, *right, *top;
struct MinHeap* minHeap = createAndBuildMinHeap(data, freq, size);
while (!isSizeOne(minHeap)) {
left = extractMin(minHeap);
right = extractMin(minHeap);
top = newNode('$', left->freq + right->freq);

top->left = left;
top->right = right;
insertMinHeap(minHeap, top);
}
return extractMin(minHeap);
}

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

{
if (root->left) {

arr[top] = 0;
printCodes(root->left, arr, top + 1);
}
if (root->right) {

arr[top] = 1;
printCodes(root->right, arr, top + 1);
}
if (isLeaf(root)) {

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


printArr(arr, top);
}
}
void HuffmanCodes(char data[], int freq[], int size)

{
struct MinHeapNode* root
= buildHuffmanTree(data, freq, size);
int arr[MAX_TREE_HT], top = 0;

printCodes(root, arr, top);


}
int main()
{ char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
int freq[] = { 5, 9, 12, 13, 16, 45 };
int size = sizeof(arr) / sizeof(arr[0]);
auto start=chrono::high_resolution_clock::now();
HuffmanCodes(arr, freq, size);
auto finish=chrono::high_resolution_clock::now();
cout<<"\nTime Taken:"<<chrono::duration_cast<chrono::nanoseconds>(finish-
start).count()<<"ns"<<endl;

return 0;
}
OUTPUT:

Experiment 11
Aim: To implement naïve string matching algorithms: Rabin Karp Algorithm and Knuth Morris
Algorithm and analyze its time complexity

Naïve String Algorithm


1. n ← length [T]
2. m ← length [P]
3. for s ← 0 to n -m
4. do if P [1.....m] = T [s + 1....s + m]
5. then print "Pattern occurs with shift" s

Code
#include<iostream>
#include <bits/stdc++.h>
using namespace std;
#include <chrono>
#include <time.h>
 
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 current index i, check for pattern match */
        for (j = 0; j < M; j++)
            if (txt[i + j] != pat[j])
                break;
 
        if (j
            == M) // if pat[0...M-1] = txt[i, i+1, ...i+M-1]
            cout << "Pattern found at index " << i << endl;
  }
}
 
// Driver's Code
int main()
{
     auto start=chrono::high_resolution_clock::now();
    char txt[] = "XYZZZAAABBLLLMMNOPQA";
    char pat[] = "LMMNO";
  
      // Function call
    search(pat, txt);
    auto finish=chrono::high_resolution_clock::now();
     cout<<"\nTime Taken:"<<chrono::duration_cast<chrono::nanoseconds>(finish-
start).count()<<"ns"<<endl;
    return 0;
}
OUTPUT

Rabin Karp Algorithm

1. n ← length [T]

2. m ← length [P]

3. h ← dm-1 mod q

4. p ← 0
5. t0 ← 0

6. for i ← 1 to m

7. do p ← (dp + P[i]) mod q

8. t0 ← (dt0+T [i]) mod q

9. for s ← 0 to n-m

10. do if p = ts

11. then if P [1.....m] = T [s+1.....s + m]

12. then "Pattern occurs with shift" s

13. If s < n-m

14. then ts+1 ← (d (ts-T [s+1]h)+T [s+m+1])mod

Code
#include<iostream>
#include <bits/stdc++.h>
using namespace std;
#include <chrono>
#include <time.h>
 
#define d 256

void search(char pat[], char txt[], int q)


{
    int M = strlen(pat);
    int N = strlen(txt);
    int i, j;
    int p = 0;
    int t = 0;
    int h = 1;
 
    for (i = 0; i < M - 1; i++)
        h = (h * d) % q;

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


        p = (d * p + pat[i]) % q;
        t = (d * t + txt[i]) % q;
  }
 
    for (i = 0; i <= N - M; i++) {
 
        if (p == t) {
            for (j = 0; j < M; j++) {
                if (txt[i + j] != pat[j]) {
                    break;
        }
      }

 
            if (j == M)
                cout << "Pattern found at index " << i
                     << endl;
    }

        if (i < N - M) {
            t = (d * (t - txt[i] * h) + txt[i + M]) % q;
 
            if (t < 0)
                t = (t + q);
    }
  }
  
}
 
/* Driver code */
int main()
{
     auto start=chrono::high_resolution_clock::now();
     char txt[] = "GEEKS FOR GEEKS";
    char pat[] = "GEEK";

    int q = INT_MAX;

    // Function Call
  
    search(pat, txt, q);
     auto finish=chrono::high_resolution_clock::now();
     cout<<"Time Taken:"<<chrono::duration_cast<chrono::nanoseconds>(finish-
start).count()<<"ns"<<endl;
    return 0;
}

Output
Knuth Morris Algorithm
1. n ← length [T]

2. m ← length [P]

3. Π← COMPUTE-PREFIX-FUNCTION (P)
4. q ← 0

5. for i ← 1 to n

6. do while q > 0 and P [q + 1] ≠ T [i]

7. do q ← Π [q]

8. If P [q + 1] = T [i]

9. then q ← q + 1

10. If q = m

11. then print "Pattern occurs with shift" i - m

12. q ← Π [q]

Code
#include<iostream>
#include <bits/stdc++.h>
using namespace std;
#include <chrono>
#include <time.h>
 
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);

    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 ((N - i) >= (M - j)) {
        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]) {
      
            if (j != 0)
                j = lps[j - 1];
            else
                i = i + 1;
    }
  }
}
 
// Fills lps[] for given pattern 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++;
      }
    }
  }
}
 
// Driver program to test above function
int main()
{
     auto start=chrono::high_resolution_clock::now();
    char txt[] = "ABABDABACDABABCABAB";
    char pat[] = "ABABCABAB";
    KMPSearch(pat, txt);
      auto finish=chrono::high_resolution_clock::now();
     cout<<"\nTime Taken:"<<chrono::duration_cast<chrono::nanoseconds>(finish-
start).count()<<"ns"<<endl;
    return 0;
}

OUTPUT

You might also like