0% found this document useful (0 votes)
96 views25 pages

Design & Analysis of Algorithms Lab

The document describes implementing linear search, binary search, and quicksort algorithms in C programming language. It includes the theory, pseudocode, and C program for each algorithm. For linear search, it searches for an item in a unsorted array. For binary search, it searches a sorted array. For quicksort, it sorts an array using the quicksort algorithm which uses partitioning. It also includes sample input/output and short answer questions about each algorithm.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
96 views25 pages

Design & Analysis of Algorithms Lab

The document describes implementing linear search, binary search, and quicksort algorithms in C programming language. It includes the theory, pseudocode, and C program for each algorithm. For linear search, it searches for an item in a unsorted array. For binary search, it searches a sorted array. For quicksort, it sorts an array using the quicksort algorithm which uses partitioning. It also includes sample input/output and short answer questions about each algorithm.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Panipat Institute of Engineering &

Technology Samalkha, Panipat

Computer Science & Engineering


Department

Practical File: Design & Analysis of Algorithms Lab


Code: PC-CS-214AL

Submitted to: Name: Prateek Kumar


Mr. Sumit Kumar Rana Roll no.: 2820140
Assistant Professor Class: B.Tech CSE 4th Sem
Department of CSE Section: C2
Practical – 1
Aim: Write a program to implement Linear Search.
Theory: In computer science, linear search or sequential search is a method for finding a
target value within a list. It sequentially checks each element of the list for the target value
until a match is found or until all the elements have been searched. Linear search runs in at
worst linear time and makes at most n comparisons, where n is the length of the list. The time
complexity of this type of search is O(n).
Algorithm:
Algorithm Linear search (a, n, item,
loc) (Here, a = is an array of n elements.
n = no. of elements.
Item = It denotes the value of the elements that is to be
searched. Loc = It returns the location of the element if present.)
1. Flag:=0;
2. Read a[1:n]
3. For(i=1 to n) step 1 do
4. { if
(a[i]=item)
Flag=1;
Break; }
5. If (flag=1)
6. Print “Element found at loc ‘i’”.
7. Else print “Element not found”.
8. Exit.

Program:
#include <stdio.h>
int main()
{
int a[50], n, loc, item, i, flag = 0;
printf("Enter the no. of elements in the array:
"); scanf("%d", &n);
printf("Enter the elements of the array: ");
for(i=0; i<n; i++)
scanf("%d", &a[i]);
printf("Enter the item to be searched:
"); scanf("%d", &item);
for(i=0; i<n; i+
+) if(a[i] ==
item)
{
flag = 1;
break;
}

if (flag == 1)
printf("\nElement found at index %d.\n", i);
else
printf("Element not found.\n");
}

Output:
1) Element Found

2) Element not found


Short Answer Questions:

Q1. What is an algorithm?


An algorithm is any well-defined computational procedure that takes some value, or set of values, as
input and produces some value, or set of values, as output. An algorithm is thus a sequence of
computational steps that transform the input into the output.

Q2. What is a linear search?


A linear search refers to the way a target key is being searched in a sequential data structure. Using
this method, each element in the list is checked and compared against the target key, and is repeated
until found or if the end of the list has been reached.

Q3. Why use sequential search?


a. If the collection size is relatively small and you would be performing this search relatively a few
times, then this might an option.
b. Another case is when the need is to have constant insertion performance (like using a linked list)
and the search frequency is less.
c. In addition, linear search places very few restrictions on the complex data types. All that is
needed is a match function of sorts.

Q4. What is best case efficiency of linear search?


The best case efficiency of linear search is O(1).

Q5. Linear search is special case of which search.


Linear search is special case of brute-force search.
Practical – 2

Aim: Write a program to implement Binary Search.


Theory: In computer science, binary search, also known as half-interval search, logarithmic
search, or binary chop, is a search algorithm that finds the position of a target value within a
sorted array. Binary search compares the target value to the middle element of the array
Algorithm:
1. Binary_Search(a, lower_bound, upper_bound, val) // 'a' is the given array, 'lower_bound' is the
index of the first array element, 'upper_bound' is the index of the last array element, 'val' is th
e value to search
2. Step 1: set beg = lower_bound, end = upper_bound, pos = - 1
3. Step 2: repeat steps 3 and 4 while beg <=end
4. Step 3: set mid = (beg + end)/2
5. Step 4: if a[mid] = val
6. set pos = mid
7. print pos
8. go to step 6
9. else if a[mid] > val
10. set end = mid - 1
11. else
12. set beg = mid + 1
13. [end of if]
14. [end of loop]
15. Step 5: if pos = -1
16. print "value is not present in the array"
17. [end of if]
18. Step 6: exit

Program:
#include <stdio.h>
int binarySearch(int a[], int beg, int end, int val)
{
int mid;
if(end >= beg)
{ mid = (beg + end)/2;
if(a[mid] == val)
{
return mid+1;
}
else if(a[mid] < val)
{
return binarySearch(a, mid+1, end, val);
}
else
{
return binarySearch(a, beg, mid-1, val);
}
}
return -1;
}

int main()
{
int a[] = {11, 14, 25, 30, 40, 41, 52, 57, 70};
int val = 40;
int n = sizeof(a) / sizeof(a[0]);
int res = binarySearch(a, 0, n-1, val);
printf("The elements of the array are - ");
for (int i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\nElement to be searched is - %d", val);
if (res == -1)
printf("\nElement is not present in the array");
else
printf("\nElement is present at %d position of array", res);
return 0;
}
Output:

Short Answer Questions:

Q1. What is an algorithm?


An algorithm is any well-defined computational procedure that takes some value, or set of values, as input and
produces some value, or set of values, as output. An algorithm is thus a sequence of computational steps that
transform the input into the output.
Q2. What is a searching algorithm?
Searching Algorithms are designed to check for an element or retrieve an element from any data structure
where it is stored.
Q3. What is Binary search?
Binary Search is a searching algorithm used in a sorted array by repeatedly dividing the search interval in half.
The idea of binary search is to use the information that the array is sorted and reduce the time complexity
Q4. What is the complexity of binary search?
The time complexity of binary search is
O(logn). Q5. What is the advantage of binary
search?
The advantage of a binary search is that it is much quicker than a serial search because the data that needs to
be searched halves with each step . For example, it is possible to search through 1024 values and find the one
you want within 10 steps, every time.
Practical – 3

Aim: Write a program to implement Quick Sort.


Theory: Quicksort is an in-place sorting algorithm. Developed by British computer scientist
Tony Hoare in 1959 and published in 1961, it is still a commonly used algorithm for sorting.
When implemented well, it can be somewhat faster than merge sort and about two or three
times faster than heapsort.
Algorithm:
Step 1 − Choose the highest index value has pivot
Step 2 − Take two variables to point left and right of the list excluding pivot
Step 3 − left points to the low index
Step 4 − right points to the high
Step 5 − while value at left is less than pivot move right
Step 6 − while value at right is greater than pivot move left
Step 7 − if both step 5 and step 6 does not match swap left and right
Step 8 − if left ≥ right, the point where they met is new pivot

Program:
#include <stdio.h>
void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
int partition(int array[], int low, int high)
{ int pivot = array[high];
int i = (low - 1);
for (int j = low; j < high; j++)
{ if (array[j] <= pivot) {
i++;
swap(&array[i], &array[j]);
}
}
swap(&array[i + 1], &array[high]);
return (i + 1);
}

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


{ if (low < high) {
int pi = partition(array, low,
high); quickSort(array, low, pi -
1);
quickSort(array, pi + 1, high);
}
}
void printArray(int array[], int size)
{ for (int i = 0; i < size; ++i) {
printf("%d | ", array[i]);
}
printf("\n");
}
int main() {
int data[] = {8, 7, 2, 1, 0, 9, 6};

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

printf("Unsorted Array: | ");


printArray(data, n);

quickSort(data, 0, n - 1);

printf("Sorted array: | ");


printArray(data, n);
}
Output:

Short Answer Questions:


Q1. What is sorting algorithm?
A Sorting Algorithm is used to rearrange a given array or list elements according to a comparison operator on
the elements. The comparison operator is used to decide the new order of element in the respective data
structure.
Q2. What is Quick Sort?
Quick Sort is a Divide and Conquer algorithm. It picks an element as pivot and partitions the given array
around the picked pivot.
Q3. What is the use of partition algorithm in Quick Sort?
The key process in Quick Sort is partition(). Target of partitions is, given an array and an element x of array as
pivot, put x at its correct position in sorted array and put all smaller elements (smaller than x) before x, and
put all greater elements (greater than x) after x. All this should be done in linear time.
Q4. When will Best Case, Worst Case and Average Case occur in Quick Sort?
i) Best Case: The best case occurs when the partition process always picks the middle element as
pivot. Following is recurrence for best case.
ii) Worst Case: The worst case occurs when the partition process always picks greatest or smallest element
as pivot. If we consider above partition strategy where last element is always picked as pivot, the worst case
would occur when the array is already sorted in increasing or decreasing order.
iii) Average Case: The average case run time of quick sort is O(n logn). This case happens when we
don’t exactly get evenly balanced partitions.
Practical – 4
Aim: Write a program to implement Merge Sort.
Theory: In computer science, merge sort is an efficient, general-purpose, and comparison-
based sorting algorithm. Most implementations produce a stable sort, which means that the
order of equal elements is the same in the input and output
Algorithm:
1. MERGE_SORT(arr, beg, end)
2. if beg < end
3. set mid = (beg + end)/2
4. MERGE_SORT(arr, beg, mid)
5. MERGE_SORT(arr, mid + 1, end)
6. MERGE (arr, beg, mid, end)
7. end of if
8. END MERGE_SORT

Program:
#include<stdio.h>
int *mergesort(int a[], int lb, int ub);
int merge(int a[], int lb, int mid, int ub, int b[]);
int main()
{
int size,i;
printf("\nEnter the size of array: ");
scanf("%d",&size);
int a[size], lb=0, ub=size-1;

printf("\nEnter the elements of the array:


"); for(i=0; i<size; i++)
scanf("%d",&a[i]);

printf("\nUnsorted Array: | ");


for(i=0; i<size; i++)
printf("%d | ",a[i]);
int *p = mergesort(a,lb,ub);
printf("\n\nSorted Array: | ");
for(i=0; i<size; i++)
printf("%d | ",p[i]); printf("\n\
n");
return 0;
}

int *mergesort(int a[], int lb, int ub)


{
int mid,i,b[ub];
if(lb<ub)
{
mid=(lb+ub)/2;
mergesort(a,lb,mid);
mergesort(a,mid+1,ub);
merge(a,lb,mid,ub,b);
}
return a; //File originally made
//by Uday Palecha.
}

int merge(int a[], int lb, int mid, int ub, int b[])
{
int i=lb,j=mid+1,k=lb;
while(i<=mid &&
j<=ub)
{
if(a[i]<=a[j])
{
b[k]=a[i];
i++;
}
else
{
b[k]=a[j];
j++;
}
k++;
}

if(i>mid)
{
while(j<=ub)
{
b[k]=a[j];
j++; k++;
}
}
else if(j>ub)
{
while(i<=mid)
{
b[k]=a[i];
i++; k++;
}
}
for(k=lb; k<=ub; k++) //Segmentation Fault occuring when b[ub] declared locally,
a[k]=b[k]; //because it was being redeclared everytime merge was
called
//and thus b[k] was going out of range.
return 0;
}

Output:
Short Answer Questions:

Q1. What is sorting algorithm?


A Sorting Algorithm is used to rearrange a given array or list elements according to a comparison
operator on the elements. The comparison operator is used to decide the new order of element in the
respective data structure.

Q2. What is merge sort?


Merge Sort is a Divide and Conquer algorithm. It divides the input array into two halves, calls
itself for the two halves, and then it merges the two sorted halves.

Q3. What is the use of merge() function in merge sort?


The merge() function is used for merging two halves. The merge(arr, l, m, r) is a key process
that assumes that arr[l..m] and arr[m+1..r] are sorted and merges the two sorted sub-arrays into
one.

Q4. What is the time complexity of merge sort?


The time complexity of merge sort is O(n logn).

Q5. What are the two methods for implementing merge sort?
i) The Top-Down (recursive) approach. Given an array of size N, the algorithm recursively breaks
the array in half and then merges the results together.
ii) The Bottom-Up (iterative) approach. Rather than breaking the overall array into distinct pieces,
bottom-up mergesort loops over the array using intervals of varying sizes. Each interval is sorted and
merged together; subsequent loops over the array have larger intervals, effectively merging our
previously sorted (smaller) intervals together.
Practical – 5
Aim: WAP to implement Longest Common Subsequence.
Theory: The longest common subsequence problem is the problem of finding the longest
subsequence common to all sequences in a set of sequences. It differs from the longest
common substring problem: unlike substrings, subsequences are not required to occupy
consecutive positions within the original sequences.
Algorithm:
X and Y be two given sequences
Initialize a table LCS of dimension X.length * Y.length
X.label = X
Y.label = Y
LCS[0][] = 0
LCS[][0] = 0
Start from LCS[1][1]
Compare X[i] and Y[j]
If X[i] = Y[j]
LCS[i][j] = 1 + LCS[i-1, j-1]
Point an arrow to LCS[i]
[j] Else
LCS[i][j] = max(LCS[i-1][j], LCS[i][j-1])
Point an arrow to max(LCS[i-1][j], LCS[i][j-1])

Program:
#include <stdio.h>
#include <string.h>

int i, j, m, n, LCS_table[20][20];
char S1[20] = "ACADB", S2[20] = "CBDA", b[20][20];

void lcsAlgo() {
m =
strlen(S1); n =
strlen(S2);

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


LCS_table[i][0] = 0;
for (i = 0; i <= n; i+
+) LCS_table[0][i] =
0;

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


for (j = 1; j <= n; j++)
{
if (S1[i - 1] == S2[j - 1]) {
LCS_table[i][j] = LCS_table[i - 1][j - 1] + 1;
} else if (LCS_table[i - 1][j] >= LCS_table[i][j - 1]) {
LCS_table[i][j] = LCS_table[i - 1][j];
} else {
LCS_table[i][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--;
}
printf("S1 : %s \nS2 : %s \n", S1, S2);
printf("LCS: %s", lcsAlgo);
}

int main() {
lcsAlgo();
printf("\n");
}

Output:

Short Answer Questions:


Q1. What is Dynamic Programming?
Dynamic Programming is mainly an optimization over plain recursion. Wherever we see a recursive
solution that has repeated calls for same inputs, we can optimize it using Dynamic Programming. The
idea is to simply store the results of subproblems, so that we do not have to re-compute them when
needed later. This simple optimization reduces time complexities from exponential to polynomial.
For example, if we write simple recursive solution for Fibonacci Numbers, we get exponential time
complexity and if we optimize it by storing solutions of subproblems, time complexity reduces to
linear.

Q2. What is LCS?


The longest common subsequence (LCS) is defined as the longest subsequence that is common to all
the given sequences, provided that the elements of the subsequence are not required to occupy
consecutive positions within the original sequences.

Q3. What is its time complexity?


Worst case time complexity: O(n*m)
Average case time complexity:
O(n*m) Best case time complexity:
O(n*m)

Q4. What is its Space Complexity?


Space complexity: O(n*m)
Practical – 6

Aim: WAP to implement Knapsack.


Theory: Here knapsack is like a container or a bag. Suppose we have given some items
which have some weights or profits. We have to put some items in the knapsack in such a
way total value produces a maximum profit.

For example, the weight of the container is 20 kg. We have to select the items in such a way
that the sum of the weight of items should be either smaller than or equal to the weight of the
container, and the profit should be maximum.

There are two types of knapsack problems:

o 0/1 knapsack problem


o Fractional knapsack problem

What is the 0/1 knapsack problem?


The 0/1 knapsack problem means that the items are either completely or no items are filled in
a knapsack. For example, we have two items having weights 2kg and 3kg, respectively. If we
pick the 2kg item then we cannot pick 1kg item from the 2kg item (item is not divisible); we
have to pick the 2kg item completely. This is a 0/1 knapsack problem in which either we
pick the item completely or we will pick that item. The 0/1 knapsack problem is solved by
the dynamic programming.

What is the fractional knapsack problem?

The fractional knapsack problem means that we can divide the item. For example, we have an
item of 3 kg then we can pick the item of 2 kg and leave the item of 1 kg. The fractional
knapsack problem is solved by the Greedy approach.

Program:
#include <stdio.h>
int main()
{
int n,i,j,bag,temp,tv=0,tw=0; printf("\
nEnter the capacity of the bag: ");
scanf("%d",&bag);
printf("\nEnter the no. of items:
"); scanf("%d",&n);

int v[n],w[n];
printf("\nEnter the value of items:
"); for(i=0; i<n; i++)
scanf("%d",&v[i]);
printf("\nEnter the weight of items accordingly:
"); for(i=0; i<n; i++)
scanf("%d",&w[i]);

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


{
for(j=0; j<n-1; j++)
{
if(v[j]<v[j+1])
{
temp=v[j]; //Sorting value of
items. v[j]=v[j+1];
v[j+1]=temp;

temp=w[j]; //Sorting weight of items


accordingly. w[j]=w[j+1];
w[j+1]=temp;
}
}
}
printf("\n\nSorted value of items: |
"); for(i=0; i<n; i++)
printf("%d | ",v[i]);
printf("\n\nAccordingly modified weight of items: | ");
for(i=0; i<n; i++)
printf("%d | ",w[i]);

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


{
if((w[i]+tw) <= bag)
{
tv+=v[i];
tw+=w[i];
}
}

printf("\n\n "); printf("\


nTotal value = %d | Total weight = %d", tv,tw);
printf("\n \n");
return 0;
}
Output:
Short Answer Questions:
Q1) What do you mean by knapsack problem?
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.

Q2) What are the approaches for knapsack problem?


So this Knapsack problem can be solved by using these following methods:
 Greedy method.

 Dynamic Programming method.

 Back Tracking method.

 Branch & Bound.

Q3) What is the importance of knapsack algorithm in our daily life?


If you are given n items of known weights and values and a knapsack capacity W, you have to find
the most subset of the items that fit into the knapsack. This problem can be use in real life for
multiple reasons, if you are moving, if you are going on a trip, or even if you are a thief. It would help
you to know how many valuable items you can take.

Q4) What is the difference between a Fractional Knapsack problem and a 0/1 Knapsack
problem?
In 0/1 knapsack problem you can either take the whole object or you take none of it whereas in
Fractional Knapsack you can take some part of it. For example if you have 1 brick in 0/1 knapsack
you can either take the whole brick or you can choose not to take it, whereas in Fractional knapsack
you can take 0.5 of it,0.6 of it i.e. any fractional part of it if you want.
Practical – 7

Aim: WAP to implement Matrix Chain Multiplication.


Theory: Matrix chain multiplication (or the matrix chain ordering problem) 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.
Algorithm:
1. n ← length[p]-1
2. for i ← 1 to n
3. do m [i, i] ← 0
4. for l ← 2 to n // l is the chain length
5. do for i ← 1 to n-l + 1
6. do j ← i+ l -1
7. m[i,j] ← ∞
8. for k ← i to j-1
9. do q ← m [i, k] + m [k + 1, j] + pi-1 pk pj
10. If q < m [i,j]
11. then m [i,j] ← q
12. s [i,j] ← k
13. return m and s.

Program:
#include <limits.h>
#include <stdio.h>
int MatrixChainOrder(int p[], int i, int j)
{
if (i == j)
return 0;
int k;
int min = INT_MAX;
int count;
for (k = i; k < j; k++)
{
count = MatrixChainOrder(p, i, k) + MatrixChainOrder(p, k + 1, j) + p[i - 1] * p[k] * p[j];
if (count < min)
min = count;
}
return min;
}
int main()
{
int arr[] = { 1, 2, 3, 4, 3 };
int n = sizeof(arr) / sizeof(arr[0]);
printf("Minimum number of multiplications is %d ", MatrixChainOrder(arr, 1, n - 1));
getchar();
return 0;
}
Output:

Short Answer Questions:

Q1) What do you mean by matrix chain multiplication?


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. Although it does not affect the product,
the order in which the terms are parenthesized affects the number of simple arithmetic operations
needed to compute the product, that is, the computational complexity.
Q2) Which of the following methods can be used to solve the matrix chain multiplication
problem?
Dynamic Programming, Brute force, Recursion methods can be used to solve the matrix chain
multiplication problem.

Q3) What is the complexity in chain matrix multiplication in dynamic programing?


However the matrix chain multiplication is a dynamic programming paradigm where we are
considering two pointers i and j which are acting as bounds for matrices that run in O(N^2). The
nested loop inside the outer loops itself takes linear time O(N). Thus, the algorithm runs in O(N^3) in
total.

Q4) What Is the Problem Statement for the Matrix Chain Multiplication Problem?
You will be given a sequence of matrices; your task will determine the most efficient technique to
multiply them together. The issue is not so much with performing the multiplications but with
determining the order in which they should be performed.

You might also like