You are on page 1of 47

1

MADHAV INSTITUTE OF TECHNOLOGY & SCIENCE, GWALIOR


(A Govt. Aided UGC Autonomous & NAAC Accredited Institute, Affiliated to RGPV, Bhopal)

Department : Information Technology


Branch : Internet of Things
Semester : 3rd
Subject : DESIGN & ANALYSIS OF ALGORITHMS 230301

PRATICAL FILE

SUBMITTED BY: SUBMITTED TO :


Rahul Kushwah prof. Vishwas shrivastava

Enrol : 0901IO201051
2

MADHAV INSTITUTE OF TECHNOLOGY & SCIENCE, GWALIOR


(A Govt. Aided UGC Autonomous & NAAC Accredited Institute, Affiliated to RGPV, Bhopal)

CONTENT
S.NO PAGE NO. REMARK
EXPERIMENT
WAP to implement the following using array as 3-20
1 data structure and analyse its time complexity.
a. Insertion sort b. Selection sort c. Bubble sort
d. Quick sort e. Merge sort f. Bucket sort g.
Shell sort h. Radix sort i. Heap sort
Write a Program to implement Linear and 21-22
2 Binary Search and analyse its time complexity.
Write a Program to implement Matrix Chain 23-24
3 Multiplication and analyses its time complexity.
Write a Program to implement Longest 25-26
4 Common Subsequence Problem and analyse its
time complexity.
Write a Program to implement Optimal Binary 27-28
5 Search Tree Problem and analyse its time
complexity.
Write a Program to implement Huffman Coding 29-33
6 and analyse its time complexity.
Write a Program to implement Dijkstra’s 34-36
7 Algorithm and analyse its time complexity.
Write a Program to implement Bellman Ford 37-40
8 Algorithm and analyses its time complexity.
Write a Program to implement DFS and BFS and 41-45
9 analyse their time complexities.
Write a Program to Implement 0/1 knapsack 46-47
10 using dynamic programming.
3

PROGRAM 1:
Write a Program to implement the following using array as data
structure and analyse its time complexity.

a. Insertion sort
CODE :
// C++ program for insertion sort
#include <bits/stdc++.h>
using namespace std;

/* Function to sort an array using insertion sort*/


void insertionSort(int arr[], int n)
{
int i, key, j;
for (i = 1; i < n; i++)
{
key = arr[i];
j = i - 1;

/* Move elements of arr[0..i-1], that are


greater than key, to one position ahead
of their current position */
while (j >= 0 && arr[j] > key)
{
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}

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


void printArray(int arr[], int n)
{
int i;
for (i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
}
4

/* Driver code */
int main()
{
int arr[] = { 9, 21, 51, 12, 90 };
int n = sizeof(arr) / sizeof(arr[0]);
cout<<"After applying Insertion sort : ";
insertionSort(arr, n);
printArray(arr, n);

return 0;
}

OUTPUT :

Time Complexity: O(n^2)


Auxiliary Space: O(1)

b. Selection sort
CODE:
// C++ program for implementation of selection sort
#include <bits/stdc++.h>
using namespace std;

void swap(int *xp, int *yp)


{
int temp = *xp;
*xp = *yp;
*yp = temp;
}

void selectionSort(int arr[], int n)


{
5

int i, j, min_idx;

// One by one move boundary of unsorted subarray


for (i = 0; i < n-1; i++)
{
// Find the minimum element in unsorted array
min_idx = i;
for (j = i+1; j < n; j++)
if (arr[j] < arr[min_idx])
min_idx = j;

// Swap the found minimum element with the first element


swap(&arr[min_idx], &arr[i]);
}
}

/* Function to print an array */


void printArray(int arr[], int size)
{
int i;
for (i=0; i < size; i++)
cout << arr[i] << " ";
cout << endl;
}

// Driver program to test above functions


int main()
{
int arr[] = {12, 45, 177,17, 82, 91};
int n = sizeof(arr)/sizeof(arr[0]);
selectionSort(arr, n);

cout << "After applying selection sort Sorted array: \n";


printArray(arr, n);
return 0;
}

OUTPUT:
6

Time Complexity: O(n2) as there are two nested loops.


Auxiliary Space: O(1)

c. Bubble sort

CODE:
// C++ program for implementation of Bubble sort

#include <bits/stdc++.h>

using namespace std;

void swap(int *xp, int *yp)

int temp = *xp;

*xp = *yp;

*yp = temp;

// A function to implement bubble sort

void bubbleSort(int arr[], int n)

int i, j;

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


7

// Last i elements are already in place

for (j = 0; j < n-i-1; j++)

if (arr[j] > arr[j+1])

swap(&arr[j], &arr[j+1]);

/* Function to print an array */

void printArray(int arr[], int size)

int i;

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

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

cout << endl;

// Driver code

int main()

int arr[] = {69, 39, 25, 12, 72, 1, 91};

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

bubbleSort(arr, n);

cout<<"After applying Bubble sort then Sorted array: \n";

printArray(arr, n);

return 0;

}
8

OUTPUT:

Worst and Average Case Time Complexity: O(n*n). Worst case occurs
when array is reverse sorted.
Best Case Time Complexity: O(n). Best case occurs when array is
already sorted.
Auxiliary Space: O(1)

d. Quick sort
CODE:
/* C++ implementation of QuickSort */
#include <bits/stdc++.h>
using namespace std;

// A utility function to swap two elements


void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}

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


{
int pivot = arr[high]; // pivot
int i = (low - 1); // Index of smaller element and indicates the right position of pivot
found so far

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


{
// If current element is smaller than the pivot
9

if (arr[j] < pivot)


{
i++; // increment index of smaller element
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);

// Separately sort elements before


// partition and after partition
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}

/* Function to print an array */


void printArray(int arr[], int size)
{
int i;
for (i = 0; i < size; i++)
cout << arr[i] << " ";
cout << endl;
}

// Driver Code
int main()
{
int arr[] = {10, 97, 38, 79, 12, 35};
int n = sizeof(arr) / sizeof(arr[0]);
quickSort(arr, 0, n - 1);
cout << "After applying Quick sort then Sorted array: \n";
printArray(arr, n);
return 0;
10

OUTPUT:

Analysis of QuickSort
Time taken by QuickSort, in general, can be written as following.
T(n) = T(k) + T(n-k-1) + (n)
Worst Case:

T(n) = T(0) + T(n-1) + (n)


which is equivalent to

T(n) = T(n-1) + (n)

The solution of above recurrence is (n2).

Best Case:
T(n) = 2T(n/2) + (n)

The solution of above recurrence is (nLogn). It can be solved using case 2 of

Average Case:
T(n) = T(n/9) + T(9n/10) + (n)
Solution of above recurrence is also O(nLogn)

e. Merge sort
CODE:
// C++ program for Merge Sort
#include <iostream>
using namespace std;

// Merges two subarrays of array[].


11

// First subarray is arr[begin..mid]


// Second subarray is arr[mid+1..end]
void merge(int array[], int const left, int const mid, int const right)
{
auto const subArrayOne = mid - left + 1;
auto const subArrayTwo = right - mid;

// Create temp arrays


auto *leftArray = new int[subArrayOne],
*rightArray = new int[subArrayTwo];

// Copy data to temp arrays leftArray[] and rightArray[]


for (auto i = 0; i < subArrayOne; i++)
leftArray[i] = array[left + i];
for (auto j = 0; j < subArrayTwo; j++)
rightArray[j] = array[mid + 1 + j];

auto indexOfSubArrayOne = 0, // Initial index of first sub-array


indexOfSubArrayTwo = 0; // Initial index of second sub-array
int indexOfMergedArray = left; // Initial index of merged array

// Merge the temp arrays back into array[left..right]


while (indexOfSubArrayOne < subArrayOne && indexOfSubArrayTwo <
subArrayTwo) {
if (leftArray[indexOfSubArrayOne] <= rightArray[indexOfSubArrayTwo]) {
array[indexOfMergedArray] = leftArray[indexOfSubArrayOne];
indexOfSubArrayOne++;
}
else {
array[indexOfMergedArray] = rightArray[indexOfSubArrayTwo];
indexOfSubArrayTwo++;
}
indexOfMergedArray++;
}
// Copy the remaining elements of
// left[], if there are any
while (indexOfSubArrayOne < subArrayOne) {
array[indexOfMergedArray] = leftArray[indexOfSubArrayOne];
indexOfSubArrayOne++;
indexOfMergedArray++;
}
12

// Copy the remaining elements of


// right[], if there are any
while (indexOfSubArrayTwo < subArrayTwo) {
array[indexOfMergedArray] = rightArray[indexOfSubArrayTwo];
indexOfSubArrayTwo++;
indexOfMergedArray++;
}
}

// begin is for left index and end is


// right index of the sub-array
// of arr to be sorted */
void mergeSort(int array[], int const begin, int const end)
{
if (begin >= end)
return; // Returns recursively

auto mid = begin + (end - begin) / 2;


mergeSort(array, begin, mid);
mergeSort(array, mid + 1, end);
merge(array, begin, mid, end);
}

// UTILITY FUNCTIONS
// Function to print an array
void printArray(int A[], int size)
{
for (auto i = 0; i < size; i++)
cout << A[i] << " ";
}

// Driver code
int main()
{
int arr[] = { 12, 11, 13, 5, 6, 7 };
auto arr_size = sizeof(arr) / sizeof(arr[0]);

cout << "Given array is \n";


printArray(arr, arr_size);

mergeSort(arr, 0, arr_size - 1);


13

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


printArray(arr, arr_size);
return 0;
}

OUTPUT:

Time Complexity: Sorting arrays on different machines. Merge Sort is a


recursive algorithm and time complexity can be expressed as following
recurrence relation.
T(n) = 2T(n/2) + θ(n)

f. Bucket sort
CODE:
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

// Function to sort arr[] of


// size n using bucket sort
void bucketSort(float arr[], int n)
{

// 1) Create n empty buckets


vector<float> b[n];

// 2) Put array elements


// in different buckets
for (int i = 0; i < n; i++) {
int bi = n * arr[i]; // Index in bucket
14

b[bi].push_back(arr[i]);
}

// 3) Sort individual buckets


for (int i = 0; i < n; i++)
sort(b[i].begin(), b[i].end());

// 4) Concatenate all buckets into arr[]


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

/* Driver program to test above function */


int main()
{
float arr[]
= { 0.897, 0.565, 0.656, 0.1234, 0.665, 0.3434 };
int n = sizeof(arr) / sizeof(arr[0]);
bucketSort(arr, n);

cout << "Sorted array is \n";


for (int i = 0; i < n; i++)
cout << arr[i] << " ";
return 0;
}

OUTPUT:

The average time complexity for Bucket Sort is O(n + k). The worst time
complexity is O(n²). The space complexity for Bucket Sort is O(n+k).
15

g. Shell sort

CODE:
// C++ implementation of Shell Sort
#include <iostream>
using namespace std;

/* function to sort arr using shellSort */


int shellSort(int arr[], int n)
{
// Start with a big gap, then reduce the gap
for (int gap = n/2; gap > 0; gap /= 2)
{
// Do a gapped insertion sort for this gap size.
// The first gap elements a[0..gap-1] are already in gapped order
// keep adding one more element until the entire array is
// gap sorted
for (int i = gap; i < n; i += 1)
{
// add a[i] to the elements that have been gap sorted
// save a[i] in temp and make a hole at position i
int temp = arr[i];

// shift earlier gap-sorted elements up until the correct


// location for a[i] is found
int j;
for (j = i; j >= gap && arr[j - gap] > temp; j -= gap)
arr[j] = arr[j - gap];

// put temp (the original a[i]) in its correct location


arr[j] = temp;
}
}
return 0;
}

void printArray(int arr[], int n)


{
for (int i=0; i<n; i++)
cout << arr[i] << " ";
}
16

int main()
{
int arr[] = {12, 34, 54, 2, 3}, i;
int n = sizeof(arr)/sizeof(arr[0]);

cout << "Array before sorting: \n";


printArray(arr, n);

shellSort(arr, n);

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


printArray(arr, n);

return 0;
}

OUTPUT:

Time Complexity: Time complexity of above implementation of


shellsort is O(n2).

h. Radix sort

CODE:
// C++ implementation of Radix Sort
#include <iostream>
using namespace std;

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


int getMax(int arr[], int n)
{
int mx = arr[0];
17

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


if (arr[i] > mx)
mx = arr[i];
return mx;
}

// A function to do counting sort of arr[] according to


// the digit represented by exp.
void countSort(int arr[], int n, int exp)
{
int output[n]; // output array
int i, count[10] = { 0 };

// Store count of occurrences in count[]


for (i = 0; i < n; i++)
count[(arr[i] / exp) % 10]++;

// Change count[i] so that count[i] now contains actual


// position of this digit in output[]
for (i = 1; i < 10; i++)
count[i] += count[i - 1];

// Build the output array


for (i = n - 1; i >= 0; i--) {
output[count[(arr[i] / exp) % 10] - 1] = arr[i];
count[(arr[i] / exp) % 10]--;
}

// Copy the output array to arr[], so that arr[] now


// contains sorted numbers according to current digit
for (i = 0; i < n; i++)
arr[i] = output[i];
}

// The main function to that sorts arr[] of size n using


// Radix Sort
void radixsort(int arr[], int n)
{
// Find the maximum number to know number of digits
int m = getMax(arr, n);
18

// Do counting sort for every digit. Note that instead


// of passing digit number, exp is passed. exp is 10^i
// where i is current digit number
for (int exp = 1; m / exp > 0; exp *= 10)
countSort(arr, n, exp);
}

// A utility function to print an array


void print(int arr[], int n)
{
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
}

// Driver Code
int main()
{
int arr[] = { 170, 45, 75, 90, 802, 24, 2, 66 };
int n = sizeof(arr) / sizeof(arr[0]);
cout<<"sorted Array :"<<endl;
// Function Call
radixsort(arr, n);
print(arr, n);
return 0;
}

OUTPUT:

Time complexity best case Ω(N k), Average case Θ(N k),
worst case O(N k), worst spaces O(N + k)
19

i. Heap sort

CODE:
// C++ program for implementation of Heap Sort
#include <iostream>

using namespace std;

// To heapify a subtree rooted with node i which is


// an index in arr[]. n is size of heap
void heapify(int arr[], int n, int i)
{
int largest = i; // Initialize largest as root
int l = 2 * i + 1; // left = 2*i + 1
int r = 2 * i + 2; // right = 2*i + 2

// If left child is larger than root


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

// If right child is larger than largest so far


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

// If largest is not root


if (largest != i) {
swap(arr[i], arr[largest]);

// Recursively heapify the affected sub-tree


heapify(arr, n, largest);
}
}

// main function to do heap sort


void heapSort(int arr[], int n)
{
// Build heap (rearrange array)
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
20

// One by one extract an element from heap


for (int i = n - 1; i > 0; i--) {
// Move current root to end
swap(arr[0], arr[i]);

// call max heapify on the reduced heap


heapify(arr, i, 0);
}
}

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


void printArray(int arr[], int n)
{
for (int i = 0; i < n; ++i)
cout << arr[i] << " ";
cout << "\n";
}

// Driver code
int main()
{
int arr[] = { 12, 11, 13, 5, 6, 7 };
int n = sizeof(arr) / sizeof(arr[0]);

heapSort(arr, n);

cout << "Sorted array is \n";


printArray(arr, n);
}

OUTPUT:

Time Complexity: Time complexity of heapify is O(Logn). Time


complexity of createAndBuildHeap() is O(n) and the overall time
complexity of Heap Sort is O(nLogn)
21

PROGRAM 2:
Write a Program to implement Linear and Binary Search and
analyse its time complexity.

CODE:
#include <iostream>
using namespace std;

int search(int arr[], int n, int x)


{
int i;
for (i = 0; i < n; i++)
if (arr[i] == x)
return i;
return -1;
}
int binarySearch(int arr[], int l, int r, int x)
{
if (r >= l) {
int mid = l + (r - l) / 2;

// If the element is present at the middle


// itself
if (arr[mid] == x)
return mid;

// If element is smaller than mid, then


// it can only be present in left subarray
if (arr[mid] > x)
return binarySearch(arr, l, mid - 1, x);

// Else the element can only be present


// in right subarray
return binarySearch(arr, mid + 1, r, x);
}

// We reach here when element is not


// present in array
return -1;
22

}
// Driver code
int main(void)
{
int arr[] = { 2, 3, 4, 10, 40 };
int x ;
cout<<"Enter the NUMBER you want to search : ";
cin>>x;
int n = sizeof(arr) / sizeof(arr[0]);

// Function call
int result = search(arr, n, x);
(result == -1)
? cout << "Element is not present in array"
: cout << "\n here we use linear search Element is present at index " << result;

int resultb = binarySearch(arr, 0, n - 1, x);


(result == -1)
? cout << "\nElement is not present in array"
: cout << "\n here we use binary search Element is present at index " << resultb;
return 0;
}

OUTPUT:

The time complexity of linear search is O(N) while binary search has O(log2N).
The best case time in linear search is for the first element i.e., O(1). As against,
in binary search, it is for the middle element, i.e., O(1).
23

PROGRAM 3:
Write a Program to implement Matrix Chain Multiplication and
analyses its time complexity.

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

// Matrix Ai has dimension p[i-1] x p[i]


// for i = 1..n
int MatrixChainOrder(int p[], int n)
{

int m[n][n];

int i, j, k, L, q;

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


m[i][i] = 0;

// L is chain length.
for (L = 2; L < n; L++)
{
for (i = 1; i < n - L + 1; i++)
{
j = i + L - 1;
m[i][j] = INT_MAX;
for (k = i; k <= j - 1; k++)
{
// q = cost/scalar multiplications
q = m[i][k] + m[k + 1][j]
+ p[i - 1] * p[k] * p[j];
if (q < m[i][j])
m[i][j] = q;
}
}
}

return m[1][n - 1];


24

// Driver Code
int main()
{
int arr[] = { 1, 2, 3, 4 };
int size = sizeof(arr) / sizeof(arr[0]);

cout << "Minimum number of multiplications is "


<< MatrixChainOrder(arr, size);

getchar();
return 0;
}

OUTPUT:

Time Complexity: O(n3 )


Auxiliary Space: O(n2)
25

PROGRAM 4:
Write a Program to implement Longest Common Subsequence
Problem and analyse its time complexity.

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

int max(int a, int b);

/* Returns length of LCS for X[0..m-1], Y[0..n-1] */


int lcs( char *X, char *Y, int m, int n )
{
if (m == 0 || n == 0)
return 0;
if (X[m-1] == Y[n-1])
return 1 + lcs(X, Y, m-1, n-1);
else
return max(lcs(X, Y, m, n-1), lcs(X, Y, m-1, n));
}

/* Utility function to get max of 2 integers */


int max(int a, int b)
{
return (a > b)? a : b;
}

/* Driver code */
int main()
{
char X[] = "RAHUL";
char Y[] = "KUSHWAH";

int m = strlen(X);
int n = strlen(Y);

cout<<"Length of LCS is "<< lcs( X, Y, m, n ) ;

return 0;
26

OUTPUT:

Time complexity of the above naive recursive approach is O(2^n) in worst case and
worst case happens when all characters of X and Y mismatch i.e., length of LCS is 0.
27

PROGRAM 5:
Write a Program to implement Optimal Binary Search Tree Problem
and analyse its time complexity.

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

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

// A recursive function to calculate


// cost of optimal binary search tree
int optCost(int freq[], int i, int j)
{
// Base cases
if (j < i) // no elements in this subarray
return 0;
if (j == i) // one element in this subarray
return freq[i];

// Get sum of freq[i], freq[i+1], ... freq[j]


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

// Initialize minimum value


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 minimum value


return min + fsum;
}

int optimalSearchTree(int keys[],


28

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

// Driver Code
int main()
{
int keys[] = {19, 9, 10};
int freq[] = {3, 8, 5};
int n = sizeof(keys) / sizeof(keys[0]);
cout << "Cost of Optimal BST is "
<< optimalSearchTree(keys, freq, n);
return 0;
}

OUTPUT:

The complexity of this algorithm is O(n3).


29

PROGRAM 6:
Write a Program to implement Huffman Coding and analyse its
time complexity.

CODE:
// Huffman Coding in C++

#include <iostream>
using namespace std;

#define MAX_TREE_HT 50

struct MinHNode {
unsigned freq;
char item;
struct MinHNode *left, *right;
};

struct MinH {
unsigned size;
unsigned capacity;
struct MinHNode **array;
};

// Creating Huffman tree node


struct MinHNode *newNode(char item, unsigned freq) {
struct MinHNode *temp = (struct MinHNode *)malloc(sizeof(struct MinHNode));

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


temp->item = item;
temp->freq = freq;

return temp;
}

// Create min heap using given capacity


struct MinH *createMinH(unsigned capacity) {
struct MinH *minHeap = (struct MinH *)malloc(sizeof(struct MinH));
minHeap->size = 0;
30

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

// Print the array


void printArray(int arr[], int n) {
int i;
for (i = 0; i < n; ++i)
cout << arr[i];

cout << "\n";


}

// Swap function
void swapMinHNode(struct MinHNode **a, struct MinHNode **b) {
struct MinHNode *t = *a;
*a = *b;
*b = t;
}

// Heapify
void minHeapify(struct MinH *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) {
swapMinHNode(&minHeap->array[smallest],
&minHeap->array[idx]);
minHeapify(minHeap, smallest);
}
31

// Check if size if 1
int checkSizeOne(struct MinH *minHeap) {
return (minHeap->size == 1);
}

// Extract the min


struct MinHNode *extractMin(struct MinH *minHeap) {
struct MinHNode *temp = minHeap->array[0];
minHeap->array[0] = minHeap->array[minHeap->size - 1];

--minHeap->size;
minHeapify(minHeap, 0);

return temp;
}

// Insertion
void insertMinHeap(struct MinH *minHeap, struct MinHNode *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;
}

// BUild min heap


void buildMinHeap(struct MinH *minHeap) {
int n = minHeap->size - 1;
int i;

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


minHeapify(minHeap, i);
}

int isLeaf(struct MinHNode *root) {


32

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


}

struct MinH *createAndBuildMinHeap(char item[], int freq[], int size) {


struct MinH *minHeap = createMinH(size);

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


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

minHeap->size = size;
buildMinHeap(minHeap);

return minHeap;
}
struct MinHNode *buildHfTree(char item[], int freq[], int size) {
struct MinHNode *left, *right, *top;
struct MinH *minHeap = createAndBuildMinHeap(item, freq, size);

while (!checkSizeOne(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 printHCodes(struct MinHNode *root, int arr[], int top) {
if (root->left) {
arr[top] = 0;
printHCodes(root->left, arr, top + 1);
}

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

cout << root->item << " | ";


printArray(arr, top);
}}

// Wrapper function
void HuffmanCodes(char item[], int freq[], int size) {
struct MinHNode *root = buildHfTree(item, freq, size);

int arr[MAX_TREE_HT], top = 0;

printHCodes(root, arr, top);


}
int main() {
char arr[] = {'A', 'B', 'C', 'D'};
int freq[] = {5, 1, 6, 3};

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

cout << "Char | Huffman code ";


cout << "\n----------------------\n";
HuffmanCodes(arr, freq, size);
}

The time complexity of the Huffman algorithm is O(nlogn)

OUTPUT:

Time complexity: O(nlogn) where n is the number of unique characters.


If there are n nodes, extractMin() is called 2*(n – 1) times. extractMin()
takes O(logn) time as it calles minHeapify(). So, overall complexity is
O(nlogn).
34

PROGRAM 7:
Write a Program to implement Dijkstra’s Algorithm and analyse its
time complexity.

CODE:
#include <iostream>
using namespace std;
#include <limits.h>

// 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


void printSolution(int dist[])
{
cout <<"Vertex \t Distance from Source" << endl;
for (int i = 0; i < V; i++)
cout << i << " \t\t"<<dist[i]<< endl;
}

// 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)
{
35

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

// driver program to test above function


int main()
{
36

/* Let us create the example graph discussed above */


int graph[V][V] = { { 0, 4, 0, 0, 0, 0, 0, 8, 0 },
{ 4, 0, 8, 0, 0, 0, 0, 11, 0 },
{ 0, 8, 0, 7, 0, 4, 0, 0, 2 },
{ 0, 0, 7, 0, 9, 14, 0, 0, 0 },
{ 0, 0, 0, 9, 0, 10, 0, 0, 0 },
{ 0, 0, 4, 14, 10, 0, 2, 0, 0 },
{ 0, 0, 0, 0, 0, 2, 0, 1, 6 },
{ 8, 11, 0, 0, 0, 0, 1, 0, 7 },
{ 0, 0, 2, 0, 0, 0, 6, 7, 0 } };

dijkstra(graph, 0);

return 0;
}

OUTPUT:

Time Complexity of Dijkstra's Algorithm is O ( V 2 )


37

PROGRAM 8:
Write a Program to implement Bellman Ford Algorithm and
analyses its time complexity.

CODE:
// A C++ program for Bellman-Ford's single source
// shortest path algorithm.
#include <bits/stdc++.h>

// a structure to represent a weighted edge in graph


struct Edge {
int src, dest, weight;
};

// a structure to represent a connected, directed and


// weighted graph
struct Graph {
// V-> Number of vertices, E-> Number of edges
int V, E;

// graph is represented as an array of edges.


struct Edge* edge;
};

// Creates a graph with V vertices and E edges


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

// A utility function used to print the solution


void printArr(int dist[], int n)
{
printf("Vertex Distance from Source\n");
for (int i = 0; i < n; ++i)
38

printf("%d \t\t %d\n", i, dist[i]);


}

// The main function that finds shortest distances from src


// to all other vertices using Bellman-Ford algorithm. The
// function also detects negative weight cycle
void BellmanFord(struct Graph* graph, int src)
{
int V = graph->V;
int E = graph->E;
int dist[V];

// Step 1: Initialize distances from src to all other


// vertices as INFINITE
for (int i = 0; i < V; i++)
dist[i] = INT_MAX;
dist[src] = 0;

// Step 2: Relax all edges |V| - 1 times. A simple


// shortest path from src to any other vertex can have
// at-most |V| - 1 edges
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;
}
}

// Step 3: check for negative-weight cycles. The above


// step guarantees shortest distances if graph doesn't
// contain negative weight cycle. If we get a shorter
// path, then there is a cycle.
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
39

&& dist[u] + weight < dist[v]) {


printf("Graph contains negative weight cycle");
return; // If negative cycle is detected, simply
// return
}
}

printArr(dist, V);

return;
}

// Driver program to test above functions


int main()
{
/* Let us create the graph given in above example */
int V = 5; // Number of vertices in graph
int E = 8; // Number of edges in graph
struct Graph* graph = createGraph(V, E);

// add edge 0-1 (or A-B in above figure)


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

// add edge 0-2 (or A-C in above figure)


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

// add edge 1-2 (or B-C in above figure)


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

// add edge 1-3 (or B-D in above figure)


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

// add edge 1-4 (or B-E in above figure)


40

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

// add edge 3-2 (or D-C in above figure)


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

// add edge 3-1 (or D-B in above figure)


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

// add edge 4-3 (or E-D in above figure)


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

BellmanFord(graph, 0);

return 0;
}

OUTPUT:

Time complexity of Bellman-Ford algorithm is Θ(|V||E|) where |V| is


number of vertices and |E| is number of edges. If the graph is complete,
the value of |E| becomes Θ(|V|2)
41

PROGRAM 9:
Write a Program to implement DFS and BFS and analyse their time
complexities.

CODE:
// C++ program to print DFS traversal from
#include <bits/stdc++.h>
using namespace std;

// Graph class represents a directed graph


// using adjacency list representation
class Graph {
public:
map<int, bool> visited;
map<int, list<int> > adj;

// function to add an edge to graph


void addEdge(int v, int w);

// DFS traversal of the vertices


// reachable from v
void DFS(int v);
};

void Graph::addEdge(int v, int w)


{
adj*v+.push_back(w); // Add w to v’s list.
}

void Graph::DFS(int v)
{
// Mark the current node as visited and
// print it
visited[v] = true;
cout << v << " ";

// Recur for all the vertices adjacent


// to this vertex
list<int>::iterator i;
42

for (i = adj[v].begin(); i != adj[v].end(); ++i)


if (!visited[*i])
DFS(*i);
}

// Driver code
int main()
{
// Create a graph given in the above diagram
Graph g;
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);

cout << "Following is Depth First Traversal"


" (starting from vertex 2) \n";
g.DFS(2);

return 0;
}

AND
// Program to print BFS traversal from a given
// source vertex. BFS(int s) traverses vertices
// reachable from s.
#include<iostream>
#include <list>

using namespace std;

// This class represents a directed graph using


// adjacency list representation
class Graph
{
int V; // No. of vertices

// Pointer to an array containing adjacency


// lists
43

list<int> *adj;
public:
Graph(int V); // Constructor

// function to add an edge to graph


void addEdge(int v, int w);

// prints BFS traversal from a given source s


void BFS(int s);
};

Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}

void Graph::addEdge(int v, int w)


{
adj*v+.push_back(w); // Add w to v’s list.
}

void Graph::BFS(int s)
{
// Mark all the vertices as not visited
bool *visited = new bool[V];
for(int i = 0; i < V; i++)
visited[i] = false;

// Create a queue for BFS


list<int> queue;

// Mark the current node as visited and enqueue it


visited[s] = true;
queue.push_back(s);

// 'i' will be used to get all adjacent


// vertices of a vertex
list<int>::iterator i;

while(!queue.empty())
44

{
// Dequeue a vertex from queue and print it
s = queue.front();
cout << s << " ";
queue.pop_front();

// Get all adjacent vertices of the dequeued


// vertex s. If a adjacent has not been visited,
// then mark it visited and enqueue it
for (i = adj[s].begin(); i != adj[s].end(); ++i)
{
if (!visited[*i])
{
visited[*i] = true;
queue.push_back(*i);
}
}
}
}

// Driver program to test methods of graph class


int main()
{
// Create a graph given in the above diagram
Graph g(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);

cout << "Following is Breadth First Traversal "


<< "(starting from vertex 2) \n";
g.BFS(2);

return 0;
}

OUTPUT:
45

The time complexity of DFS if the entire tree is traversed is O(V) where V is the number of nodes.

The Time complexity of BFS is O(V + E) when Adjacency List is used and O(V^2) when Adjacency
Matrix is used, where V stands for vertices and E stands for edges.
46

PROGRAM 10:
Write a Program to Implement 0/1 knapsack using dynamic
programming.

CODE:
// A dynamic programming based
// solution for 0-1 Knapsack problem
#include <bits/stdc++.h>
using namespace std;

// A utility function that returns


// maximum of two integers
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;
vector<vector<int>> K(n + 1, vector<int>(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];
}
}
47

return K[n][W];
}

// Driver Code
int main()
{
int val[] = { 60, 100, 120 };
int wt[] = { 10, 20, 30 };
int W = 50;
int n = sizeof(val) / sizeof(val[0]);

cout << knapSack(W, wt, val, n);

return 0;
}

OUTPUT:

Complexity Analysis:
 Time Complexity: O(N*W).
where ‘N’ is the number of weight element and ‘W’ is capacity. As for
every weight element we traverse through all weight capacities 1<=w<=W.
 Auxiliary Space: O(N*W).
The use of 2-D array of size ‘N*W’

You might also like