0% found this document useful (0 votes)
49 views

CSE2012 Lab Assignment 1

The document discusses three algorithms: 1. Merge sort is used to sort 10 numbers using divide and conquer. It has time complexity of O(n log n) and space complexity of O(n). 2. Huffman coding is used for lossless data compression. It assigns variable length codes to characters based on frequency. The algorithm builds a Huffman tree and traverses it to generate codes. 3. The N queens problem places N queens on an N×N chessboard so that no two queens attack each other. Backtracking is used to solve this by trying all possible placements of queens.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
49 views

CSE2012 Lab Assignment 1

The document discusses three algorithms: 1. Merge sort is used to sort 10 numbers using divide and conquer. It has time complexity of O(n log n) and space complexity of O(n). 2. Huffman coding is used for lossless data compression. It assigns variable length codes to characters based on frequency. The algorithm builds a Huffman tree and traverses it to generate codes. 3. The N queens problem places N queens on an N×N chessboard so that no two queens attack each other. Backtracking is used to solve this by trying all possible placements of queens.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 22

CSE2012 - Design and Analysis of Algorithms

Lab Assessment-1

Name: - 20BCE2309 Sai Chakradar M


20BCE0530 Rahulkumar Ankola
Submitted to: Dr. Sivanesan S
Date :- 09/09/2021
Slot: - L19+L20
1. Divide And Conquer – Merge Sort

Aim: Sorting 10 numbers by using Merge Sort


Problem Analysis:

Divide and Conquer


Merge sort is a technique which we are going to use. Merge Sort can be performed by using
divide and Conquer. Divide and Conquer can be divided into 3 parts:
Divide: The problem is divided into small or sub parts!
Conquer: The sub parts are solved separately by calling them recursively until they are
solved!
Combine: In the previous step all the parts are solved and in this step all are combined to
solve the problem!
To Sort all the elements in a given array we use divide and conquer. After the problem is
solved we will be able to see all the numbers in the array will be arranged ascending order!
Now we are going to use divide and conquer to solve merge sort!
Flowchart:

Pseudo code:
1. Declare left and right var which will mark the extreme indices of the array
2. Left will be assigned to 0 and right will be assigned to n-1
3. Find mid = (left+right)/2
4. Above will continue till left<right
5. Then we will call merge on the 2 sub problems
Algorithm:

Mergersort(arr,left,right):

If left>right

Return

Mid=(left+right)/2

Mergesort(arr,left,mid)

Mergersort(arr,mid+1,RIGHT)

Mergesort(arr,left,mid,right); end

Code:

#include <stdlib.h>
#include <stdio.h>

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


{
int i, j, k;
int n1 = m - l + 1, 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 = (r + l) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}

int main()
{
int a[20], s, i, j, n, key;
printf("Enter array size: ");
scanf("%d", &s);
printf("Enter array to sort: ");
for (i = 0; i < s; i++)
scanf("%d", &a[i]);

mergeSort(a, 0, s - 1);
printf("\nSorted array: ");
for (i = 0; i < s; i++)
printf("%d ", a[i]);
return 0;
}
Input & Output:

Complexity Analysis:
Time complexity analysis:
In the merge() function it iterates over a array and the arrays can have at most size of n.
Rest of the process we are just comparing and assigning values and they are constant time
process. Thus merge() has a running time of O(n).
Now for the mergesort() function, it is breaking the problem size of n into two
subproblems of size n/2 each. The comparision and calculation in the middle are
constant time taking process. So the time complexity of merge-sort algorithm will be:
Space complexity analysis:
In the merge phase, elements from two subarrays are copied into a new array. In the
last step, the new array is exactly as large as the array to be sorted. Thus we have a
linear requirement.
The space complexity of Merge Sort is O(n)

Result:

Time Complexity: O(n*log(n)).


Space Complexity: O(n)
We have sorted all the elements in the array using divide and conquer!
2. Greedy Technique – Huffman Coding

Aim: To Write A Program for Huffman Coding with proper Algorithm and Flowchart.

Problem Analysis: Huffman coding is a greedy algorithm which is used for lossless
compression of data. It reduces the number of bits without removing the data. The
algorithm is based on frequency of the characters appearing in a file. Our computer stores
our files as binary code and each character has a binary character and this characters are of
fixed length.

Here in Huffman coding it doesn’t use fixed length for each character it assigns the length
based on the frequency! It assigns a short length for the character that comes more time!
Since characters which have high frequency has lower length, they take less space and save
the space required to store the file.

Pesucode & Algorithm:

Huffman (C)
-> n=|C|
-> Q ← C
-> for i=1 to n-1
-> do
-> z= allocate-Node ()
-> x= left[z]=Extract-Min(Q)
-> y= right[z] =Extract-Min(Q)
-> f [z]=f[x]+f[y]
-> Insert (Q, z)
->return Extract-Min (Q)

1. Determine the count of each symbol in the input message.


2. Create a forest of single-node trees. Each node in the initial forest represents a symbol
from the set of possible symbols, and contains the count of that symbol in the message to
be coded. Symbols with a count of zero are ignored (consider them to be impossible).

3. Loop while there is more than 1 tree in the forest:

4. Remove the two trees from the forest that have the lowest count contained in their roots.

5. Create a new node that will be the root of a new tree. This new tree will have those two
trees just removed in step 2a as left and right subtrees. The count in the root of this new
tree will be the sum of the counts in the roots of its subtrees. Label the edge from this new
root to its left subtree “1”, and label the edge to its right subtree “0”.

6. Insert this new tree in the forest, and go to 2.

7. Return the one tree in the forest as the Huffman code tree.

Flowchart:
Code:

#include <iostream>
using namespace std;

#define MAX 50

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

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

struct MinHNode *newNode(char item, unsigned freq)


{
struct MinHNode *temp = (struct MinHNode *)malloc(sizeof(struct MinHN
ode));

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


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

return temp;
}

struct MinH *createMinH(unsigned capacity)


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

void swap(struct MinHNode **a, struct MinHNode **b)


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

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)
{
swap(&minHeap->array[smallest], &minHeap->array[idx]);
minHeapify(minHeap, smallest);
}
}

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

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

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)


{
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 (minHeap->size != 1)
{
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 printHuffmanCodes(struct MinHNode *root, int a[], int top)


{
if (root->left)
{
a[top] = 0;
printHuffmanCodes(root->left, a, top + 1);
}

if (root->right)
{
a[top] = 1;
printHuffmanCodes(root->right, a, top + 1);
}
if (isLeaf(root))
{
cout << root->item << " --> ";
for (int i = 0; i < top; ++i)
cout << a[i];
cout << endl;
}
}

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


{
struct MinHNode *root = buildHfTree(item, freq, size);

int a[MAX], top = 0;


printHuffmanCodes(root, a, top);
}

int main()
{
char a[] = {'R', 'B', 'C', 'S', 'A', 'Z'};
int freq[] = {9, 7, 16, 32, 1, 42};

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

cout << "Huffman codes are as following: \n";


HuffmanCodes(a, freq, size);
return 0;
}
Input & Output:

Result: Hence, we have proved Huffman coding with greedy Algorithm! We have succefully
have compressed the data with removing any data.
3. Backtracking – N Queens Problem

Aim: Place n-queens in N*N chess board so that no of them can attack i.e. no of them are on
the same row, column or diagonal!
Problem Analysis:
We Use Backtracking to solve this N Queens Problem. You are given an 8x8 chessboard, find
a way to place 8 queens such that no queen can attack any other queen on the chessboard.
A queen can only be attacked if it lies on the same row, or same column, or the same
diagonal of any other queen. Print all the possible configurations.

To solve this problem, we will make use of the Backtracking algorithm. The backtracking
algorithm, in general checks all possible configurations and test whether the required result
is obtained or not. For thr given problem, we will explore all possible positions the queens
can be relatively placed at. The solution will be correct when the number of placed queens =
8.
Backtracking happens for either of two reasons:

 no value can be assigned to the next variable due to constraints


 value cannot be further assigned if a solution is found

Pesucode & Algorithm:


1) Start in the leftmost column
2) If all queens are placed return true
3) Try all rows in the current column.
Do following for every tried row.
a) If the queen can be placed safely in this row then mark this [row, column] as part of
the solution and recursively check if placing queen here leads to a solution.
b) If placing the queen in [row, column] leads to a solution then return true.
c) If placing queen doesn't lead to a solution then unmark this [row, column] (Backtrack)
and go to step (a) to try other rows.
4) If all rows have been tried and nothing worked, return false to trigger backtracking.
Flowchart:
Code:

#define N 5
#include <stdbool.h>
#include <stdio.h>

bool isSafe(int board[N][N], int row, int col)


{
int i, j;
for (i = 0; i < col; i++)
if (board[row][i])
return false;

for (i = row, j = col; i >= 0 && j >= 0; i--, j--)


if (board[i][j])
return false;

for (i = row, j = col; j >= 0 && i < N; i++, j--)


if (board[i][j])
return false;

return true;
}

bool solveNQUtil(int board[N][N], int col)


{
if (col >= N)
return true;

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


{
if (isSafe(board, i, col))
{
board[i][col] = 1;

if (solveNQUtil(board, col + 1))


return true;

board[i][col] = 0;
}
}

return false;
}

bool solveNQ()
{
int board[N][N] = {{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}};

if (solveNQUtil(board, 0) == false)
{
printf("Solution does not exist");
return false;
}

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


{
for (int j = 0; j < N; j++)
printf(" %d ", board[i][j]);
printf("\n");
}
return true;
}

int main()
{
solveNQ();
return 0;
}

Input and output:


Complexity Analysis:
Time Complexity analysis:
The for loop in solveNQUtil() is running from 1 to n but the recursive call of solveNQUtil()
will not only run for the safe cells i.e T(n-1). So this part will take n*T(n-1) time
Also the for loop in solveNQUtil() calls the function isSafe() and the function has a O(n)
worst case running time. And inside the function the for loop runs for n times. So this part
will take O(n*n) time.
Thus,

Space complexity analysis:


The algorithm uses a matrix to store the chess board positions.
The space complexity of N Queens Problem is O(n*n)

Result:
Time complexity: O(n!)
Space complexity: O(n*n)
We Have placed n-qeens N * N chess board so that no of them can attack i.e. no of them are
on the same row, column or diagonal! Using backtracking!
Complexity Analysis Table:

Name of Name of Time Space Ranking


Techniques sample complexity Complexity based
Algorithm (in Big O (in bytes) on the
notations) complexities
Divide and Merge Sort O(nlogn) O(n) 2
Conquer
Backtracking N Queens O(n!) O(n*n) 1
Problem

Optimization for N Queens Problem:


The idea is not to check every element in right and left diagonal instead use property of
diagonals:

1.The sum of i and j is constant and unique for each right diagonal where i is the row of
element and j is the
column of element.
2.The difference of i and j is constant and unique for each left diagonal where i and j are row
and column of element respectively.
Code:

#include <stdbool.h>
#include <stdio.h>

#define N 5
int r_diag[N] = { 0 };
int l_diag[N] = { 0 };
int cl[N*N] = { 0 };

bool solveNQUtil(int board[N][N], int col)


{
if (col >= N)
return true;
for (int i = 0; i < N; i++)
if ((l_diag[i - col + N - 1] != 1 && r_diag[i + col] != 1) && c
l[i] != 1)
{
board[i][col] = 1;
l_diag[i - col + N - 1] = r_diag[i + col] = cl[i] = 1;

if (solveNQUtil(board, col + 1))


return true;

board[i][col] = 0;
l_diag[i - col + N - 1] = r_diag[i + col] = cl[i] = 0;
}
return false;
}
void solveNQ()
{
int board[N][N] = { { 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 } };

if (solveNQUtil(board, 0))
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
printf(" %d ", board[i][j]);
printf("\n");
}
else printf("Solution does not exist");
}

int main()
{
solveNQ();
return 0;
}
Input and Output:

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy