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

DAAlab_file

The document provides an introduction to algorithms, focusing on their design, analysis, and characteristics. It outlines various algorithm design techniques such as recursive, divide and conquer, dynamic programming, and greedy methods, along with the importance of analyzing algorithms for time and space complexity. Additionally, it includes practical programming examples for different sorting algorithms and problem-solving techniques.

Uploaded by

ctanishka100
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

DAAlab_file

The document provides an introduction to algorithms, focusing on their design, analysis, and characteristics. It outlines various algorithm design techniques such as recursive, divide and conquer, dynamic programming, and greedy methods, along with the importance of analyzing algorithms for time and space complexity. Additionally, it includes practical programming examples for different sorting algorithms and problem-solving techniques.

Uploaded by

ctanishka100
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 24

INTRODUCTION TO DESIGN AND ANALYSIS OF

ALGORITHMS

An algorithm is a set of steps of operations to solve a problem performing


calculation, data processing, and automated reasoning tasks. It is an efficient
method that can be expressed within finite amount of time and space. An
algorithm is the best way to represent the solution of a particular problem in a
very simple and efficient way. If we have an algorithm for a specific problem,
then we can implement it in any programming language, meaning that
the algorithm is independent from any programming languages.

Algorithm Design:
The important aspects of algorithm design include creating an efficient algorithm
to solve a problem in an efficient way using minimum time and space. To solve a
problem, different approaches can be followed. Some of them can be efficient
with respect to time consumption, whereas other approaches may be memory
efficient. However, one has to keep in mind that both time consumption and
memory usage cannot be optimized simultaneously.

Problem Development Steps: The following steps are involved in solving


computational problems.
​ Problem definition
​ Development of a model
​ Specification of an Algorithm
​ Designing an Algorithm
​ Checking the correctness of an Algorithm
​ Analysis of an Algorithm
​ Implementation of an Algorithm
​ Program testing
​ Documentation

Characteristics of Algorithms: The main characteristics of algorithms are as


follows:
​ Algorithms must have a unique name
​ Algorithms should have explicitly defined set of inputs and outputs
​ Algorithms are well-ordered with unambiguous operations
​ Algorithms halt in a finite amount of time. Algorithms should not run for
infinity, i.e., an algorithm must end at some point
Algorithm Analysis: Algorithm analysis is an important part of computational
complexity theory, which provides theoretical estimation for the required resources
of an algorithm to solve a specific computational problem. Analysis of algorithms
is the determination of the amount of time and space resources required to execute
it.

The Need for Analysis: Algorithms are often quite different from one another,
though the objectives of these algorithms are the same. Analysis of algorithm is the
process of analyzing the problem-solving capability of the algorithm in terms of
the time and size required. Generally, the following types of analysis are
performed −
​ Worst-case − the maximum number of steps taken on any instance of size a.
​ Best-case − the minimum number of steps taken on any instance of size a.
​ Average case − the average number of steps taken on any instance of size a.

Complexity of an algorithm is analyzed in two perspectives: Time and Space:


Time Complexity: It’s a function describing the amount of time required to run an
algorithm in terms of the size of the input.
Space Complexity: It’s a function describing the amount of memory an algorithm
takes in terms of the size of input to the algorithm.

Asymptotic Notations: Execution time of an algorithm depends on the instruction


set, processor speed, disk I/O speed, etc. Hence, we estimate the efficiency of an
algorithm asymptotically. Different types of asymptotic notations are used to
represent the complexity of an algorithm. Following asymptotic notations are used
to calculate the running time complexity of an algorithm.
​ O − Big Oh
​ Ω − Big omega
​ θ − Big theta
​ o − Little Oh
​ ω − Little omega
Algorithm Design Techniques: The following is a list of several popular design
approaches:
​ Recursive
​ Divide and Conquer
​ Dynamic Programming
​ Greedy Technique
​ Brute Force
​ Backtracking
​ Branch and Bound

Recursive Algorithm: This is one of the most interesting Algorithms as it calls


itself with a smaller value as inputs which it gets after solving for the current
inputs. In simpler words, it’s an Algorithm that calls itself repeatedly until the
problem is solved.
Problems such as the Tower of Hanoi or DFS of a Graph can be easily solved by
using these Algorithms.

Divide and Conquer: This is another effective way of solving many problems. In
Divide and Conquer algorithms, divide the algorithm into two parts; the first parts
divide the problem on hand into smaller sub problems of the same type. Then, in
the second part, these smaller problems are solved and then added together
(combined) to produce the problem’s final solution.
Problems such as Binary Search, Quick Sort, and Merge Sort can be solved using
this technique.

Dynamic Programming: These algorithms work by remembering the results of


the past run and using them to find new results. In other words, a dynamic
programming algorithm solves complex problems by breaking them into multiple
simple sub problems and then it solves each of them once and then stores them for
future use. Dynamic Programming is frequently related to Optimization Problems.
Problems such as Multistage Graphs, Optimal Binary Search Tress can be solved
using this technique.

Greedy Technique: This is used to solve the optimization problem. An


optimization problem is one in which there is a given a set of input values, which
are required either to be maximized or minimized (known as objective), i.e. some
constraints or conditions. It always makes the choice (greedy criteria) looks best at
the moment, to optimize a given objective. It doesn't always guarantee the optimal
solution however it generally produces a solution that is very close in value to the
optimal.
Problems such as Kruskal’s Minimum Spanning Tree (MST), Prim's Minimal
Spanning Tree, Dijkstra's Minimal Spanning Tree and Knapsack Problem can be
solved using this technique.

Brute Force Algorithm: This is one of the simplest algorithms in the concept. A
brute force algorithm blindly iterates all possible solutions to search one or more
than one solution that may solve a function. Think of brute force as using all
possible combinations of numbers to open a safe.
Problems such as Selection Sort, convex hull can be solved using this technique.

Backtracking Algorithm: Backtracking is a technique to find a solution to a


problem in an incremental approach. It solves problems recursively and tries to
solve a problem by solving one piece of the problem at a time. If one of the
solutions fails, we remove it and backtrack to find another solution. In other words,
a backtracking algorithm solves a sub problem, and if it fails to solve the problem,
it undoes the last step and starts again to find the solution to the problem.
N-Queens problem is one good example to see Backtracking algorithm in action.

Branch and Bound: In Branch & Bound algorithm a given sub problem, which
cannot be bounded, has to be divided into at least two new restricted sub problems.
Branch and Bound algorithm are methods for global optimization in non-convex
problems. Branch and Bound algorithms can be slow, however in the worst case
they require effort that grows exponentially with problem size.
LIST OF LAB PROGRAMS

SNO PROGRAM DATE SIGN


Program for Recursive Binary & Linear Search

1.
Program for Heap Sort.
2.
Program for Merge Sort.
3.
4. Program for Selection Sort.

Program for Insertion Sort.


5.
Program for Quick Sort.
6.

Knapsack Problem using Greedy Solution


7.

Perform Travelling Salesman Problem


8.

Find Minimum Spanning Tree using Kruskal’s


9. Algorithm

Implement N Queen Problem using Backtracking


10.
Program :1

Binary search in C using recursion

#include <stdio.h>
int binarySearch(int [], int, int, int);

int main()
{
int c, first, last, n, search, array[100], index;

printf("Enter number of elements\n");


scanf("%d", &n);

printf("Enter %d integers\n", n);

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


scanf("%d", &array[c]);

printf("Enter value to find\n");


scanf("%d", &search);

first = 0;
last = n - 1;

index = binarySearch(array, first, last, search);

if (index == -1)
printf("Not found! %d isn't present in the list.\n", search);
else
printf("%d is present at location %d.\n", search, index + 1);

return 0;
}

int binarySearch(int a[], int s, int e, int f) {


int m;

if (s > e) // Not found


return -1;

m = (s + e)/2;

if (a[m] == f) // element found


return m;
else if (f > a[m])
return binarySearch(a, m+1, e, f);
else
return binarySearch(a, s, m-1, f);
}

Linear Search

#include<stdio.h>
int Linear_search(int arr[], int Search_ele, int n)
{
int i;
static int temp=0;
if(n>0)
{
i=n-1;
if(arr[i]==Search_ele)
temp=1;
Linear_search(arr,Search_ele,i);
}
return temp;
}
int main()
{
int n,j;
printf("Enter your array size:");
scanf("%d",&n);
int arr[n];
printf("Enter the Array Element:");
for(j=0;j<n;j++)
{
scanf("%d",&arr[j]);
}
int Search_ele;
printf("Enter the search element:");
scanf("%d",&Search_ele);
if(Linear_search(arr,Search_ele,n)==1)
printf("Element found....");
else
printf("Element not found....");
return 0;
}
Program -2 :

#include<stdio.h>
#include <conio.h>
void heapify_function(int arr[])
{
int i,n;
n=arr[0];
for(i=n/2;i>=1;i--)
adjust(arr,i);
}
void adjust(int arr[],int i)
{
int j,temp,n,k=1;
n=arr[0];
while(2*i<=n && k==1)
{
j=2*i;
if(j+1<=n && arr[j+1] > arr[j])
j=j+1;

if( arr[j] < arr[i])


k=0;
else
{
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
i=j;
}
}
}

void main()
{
int arr[100],n,temp,last,i;
clrscr();
printf("How many Numbers you want to enter in your array: \n");
scanf("%d",&n);
printf("Enter Elements in array:\n");
for(i=1;i<=n;i++)
scanf("%d",&arr[i]);
arr[0]=n;
heapify_function(arr);
while(arr[0] > 1)
{
last=arr[0];
temp=arr[1];
arr[1]=arr[last];
arr[last]=temp;
arr[0]--;
adjust(arr,1);
}

printf("Array After Heap Sort\n");


for(i=1;i<=n;i++)
printf("%d ",arr[i]);
getch();
}
Program 3:

#include <stdio.h>

#define max 10

int a[11] = { 10, 14, 19, 26, 27, 31, 33, 35, 42, 44, 0 };
int b[10];

void merging(int low, int mid, int high) {


int l1, l2, i;

for(l1 = low, l2 = mid + 1, i = low; l1 <= mid && l2 <= high; i++) {
if(a[l1] <= a[l2])
b[i] = a[l1++];
else
b[i] = a[l2++];
}

while(l1 <= mid)


b[i++] = a[l1++];

while(l2 <= high)


b[i++] = a[l2++];

for(i = low; i <= high; i++)


a[i] = b[i];
}

void sort(int low, int high) {


int mid;

if(low < high) {


mid = (low + high) / 2;
sort(low, mid);
sort(mid+1, high);
merging(low, mid, high);
} else {
return;
}
}

int main() {
int i;
printf("List before sorting\n");

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


printf("%d ", a[i]);

sort(0, max);

printf("\nList after sorting\n");

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


printf("%d ", a[i]);
}
Program 4:

#include <stdio.h>
int main()
{
int a[100], n, i, j, position, swap;
printf("Enter number of elementsn");
scanf("%d", &n);
printf("Enter %d Numbersn", n);
for (i = 0; i < n; i++)
scanf("%d", &a[i]);
for(i = 0; i < n - 1; i++)
{
position=i;
for(j = i + 1; j < n; j++)
{
if(a[position] > a[j])
position=j;
}
if(position != i)
{
swap=a[i];
a[i]=a[position];
a[position=swap;
}
}
printf("Sorted Array:n");
for(i = 0; i < n; i++)
printf("%dn", a[i]);
return 0;
}
Program 5:

#include <stdio.h>

int main()
{
int n, array[1000], c, d, t, flag = 0;

printf("Enter number of elements\n");


scanf("%d", &n);

printf("Enter %d integers\n", n);

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


scanf("%d", &array[c]);

for (c = 1 ; c <= n - 1; c++) {


t = array[c];

for (d = c - 1 ; d >= 0; d--) {


if (array[d] > t) {
array[d+1] = array[d];
flag = 1;
}
else
break;
}
if (flag)
array[d+1] = t;
}

printf("Sorted list in ascending order:\n");

for (c = 0; c <= n - 1; c++) {


printf("%d\n", array[c]);
}

return 0;
}
Program 6:

#include <stdio.h>

void quick_sort(int[],int,int);
int partition(int[],int,int);

int main()
{
int a[50],n,i;
printf("How many elements?");
scanf("%d",&n);
printf("\nEnter array elements:");
for(i=0;i<n;i++)
scanf("%d",&a[i]);
quick_sort(a,0,n-1);
printf("\nArray after sorting:");
for(i=0;i<n;i++)
printf("%d ",a[i]);
return 0;
}

void quick_sort(int a[],int l,int u)


{
int j;
if(l<u)
{
j=partition(a,l,u);
quick_sort(a,l,j-1);
quick_sort(a,j+1,u);
}
}

int partition(int a[],int l,int u)


{
int v,i,j,temp;
v=a[l];
i=l;
j=u+1;
do
{
do
i++;
while(a[i]<v&&i<=u);
do
j--;
while(v<a[j]);
if(i<j)
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}while(i<j);
a[l]=a[j];
a[j]=v;
return(j);
}
Program 7:

# include<stdio.h>

void knapsack(int n, float weight[], float profit[], float capacity) {


float x[20], tp = 0;
int i, j, u;
u = capacity;

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


x[i] = 0.0;

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


if (weight[i] > u)
break;
else {
x[i] = 1.0;
tp = tp + profit[i];
u = u - weight[i];
}
}

if (i < n)
x[i] = u / weight[i];

tp = tp + (x[i] * profit[i]);

printf("\nThe result vector is:- ");


for (i = 0; i < n; i++)
printf("%f\t", x[i]);

printf("\nMaximum profit is:- %f", tp);

int main() {
float weight[20], profit[20], capacity;
int num, i, j;
float ratio[20], temp;

printf("\nEnter the no. of objects:- ");


scanf("%d", &num);

printf("\nEnter the wts and profits of each object:- ");


for (i = 0; i < num; i++) {
scanf("%f %f", &weight[i], &profit[i]);
}

printf("\nEnter the capacityacity of knapsack:- ");


scanf("%f", &capacity);

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


ratio[i] = profit[i] / weight[i];
}

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


for (j = i + 1; j < num; j++) {
if (ratio[i] < ratio[j]) {
temp = ratio[j];
ratio[j] = ratio[i];
ratio[i] = temp;

temp = weight[j];
weight[j] = weight[i];
weight[i] = temp;

temp = profit[j];
profit[j] = profit[i];
profit[i] = temp;
}
}
}

knapsack(num, weight, profit, capacity);


return(0);
}
Program 8:

#include<stdio.h>

int ary[10][10],completed[10],n,cost=0;

void takeInput()
{
int i,j;

printf("Enter the number of villages: ");


scanf("%d",&n);

printf("\nEnter the Cost Matrix\n");

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


{
printf("\nEnter Elements of Row: %d\n",i+1);

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


scanf("%d",&ary[i][j]);

completed[i]=0;
}

printf("\n\nThe cost list is:");

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


{
printf("\n");

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


printf("\t%d",ary[i][j]);
}
}

void mincost(int city)


{
int i,ncity;

completed[city]=1;

printf("%d--->",city+1);
ncity=least(city);
if(ncity==999)
{
ncity=0;
printf("%d",ncity+1);
cost+=ary[city][ncity];

return;
}

mincost(ncity);
}

int least(int c)
{
int i,nc=999;
int min=999,kmin;

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


{
if((ary[c][i]!=0)&&(completed[i]==0))
if(ary[c][i]+ary[i][c] < min)
{
min=ary[i][0]+ary[c][i];
kmin=ary[c][i];
nc=i;
}
}

if(min!=999)
cost+=kmin;

return nc;
}

int main()
{
takeInput();

printf("\n\nThe Path is:\n");


mincost(0); //passing 0 because starting vertex

printf("\n\nMinimum cost is %d\n ",cost);

return 0;
}
Program 9:

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
int i,j,k,a,b,u,v,n,ne=1;
int min,mincost=0,cost[9][9],parent[9];
int find(int);
int uni(int,int);
void main()
{
clrscr();
printf("\n\tImplementation of Kruskal's algorithm\n");
printf("\nEnter the no. of vertices:");
scanf("%d",&n);
printf("\nEnter the cost adjacency matrix:\n");
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&cost[i][j]);
if(cost[i][j]==0)
cost[i][j]=999;
}
}
printf("The edges of Minimum Cost Spanning Tree are\n");
while(ne < n)
{
for(i=1,min=999;i<=n;i++)
{
for(j=1;j <= n;j++)
{
if(cost[i][j] < min)
{
min=cost[i][j];
a=u=i;
b=v=j;
}
}
}
u=find(u);
v=find(v);
if(uni(u,v))
{
printf("%d edge (%d,%d) =%d\n",ne++,a,b,min);
mincost +=min;
}
cost[a][b]=cost[b][a]=999;
}
printf("\n\tMinimum cost = %d\n",mincost);
getch();
}
int find(int i)
{
while(parent[i])
i=parent[i];
return i;
}
int uni(int i,int j)
{
if(i!=j)
{
parent[j]=i;
return 1;
}
return 0;
}
Program 10:

#include<stdio.h>
#include<math.h>

char a[10][10];
int n;

void printmatrix() {
int i, j;
printf("\n");

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


for (j = 0; j < n; j++)
printf("%c\t", a[i][j]);
printf("\n\n");
}
}

int getmarkedcol(int row) {


int i;
for (i = 0; i < n; i++)
if (a[row][i] == 'Q') {
return (i);
break;
}
}

int feasible(int row, int col) {


int i, tcol;
for (i = 0; i < n; i++) {
tcol = getmarkedcol(i);
if (col == tcol || abs(row - i) == abs(col - tcol))
return 0;
}
return 1;
}

void nqueen(int row) {


int i, j;
if (row < n) {
for (i = 0; i < n; i++) {
if (feasible(row, i)) {
a[row][i] = 'Q';
nqueen(row + 1);
a[row][i] = '.';
}
}
} else {
printf("\nThe solution is:- ");
printmatrix();
}
}

int main() {
int i, j;

printf("\nEnter the no. of queens:- ");


scanf("%d", &n);

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


for (j = 0; j < n; j++)
a[i][j] = '.';

nqueen(0);
return (0);
}

You might also like