5th Sem ADA Manual

41
5 th semester ADA lab 1 5 th SEMESTER ISE MANUAL FOR ANALYSIS AND DESIGN OF LIST OF PROGRAMS 1. Implement Recursive Binary search and Linear search and determine the time required to search an element. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n . 2. Sort a given set of elements using the Heapsort method and determine the time required to sort the elements. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n . 3. Sort a given set of elements using Merge sort method and determine the time required to sort the elements. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n . 4. Sort a given set of elements using Selection sort and determine the time required to sort the elements. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n . 5. a. Obtain the topological ordering of vertices in a given digraph. b. Implement All Pair Shortest paths problem using Floyd’s algorithm. 6. Implement the 0/1 knapsack problem using dynamic S s 1 , s 2 of n positive numbers whose a given positive number d . S ,1 an d 9 , solutions and . A suitable message is to be instance does not have a solution. 12. a. Implement Horspool algorithm for String Matching. b. Find the Binomial Co-efficients using Dynamic Programming. 13. Find the Minimum Cost Spanning Tree of a given undirected graph using Prim’s algorithm. 14. a. Implement Floyd’s algorithm for the All-Pairs-Shortest- Paths problem. b. Compute the transitive closure of a given directed graph using Warshall’s algorithm. NOTE: In the examination, questions must be BNMIT ISE

Transcript of 5th Sem ADA Manual

Page 1: 5th Sem ADA Manual

5 th semester ADA lab 1

5th SEMESTER ISE MANUAL FOR ANALYSIS AND DESIGN OF ALGORITHMS (ADA) LAB

LIST OF PROGRAMS

1. Implement Recursive Binary search and Linear search and determine the time required to search an element. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n .

2. Sort a given set of elements using the Heapsort method and determine the time required to sort the elements. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n .

3. Sort a given set of elements using Merge sort method and determine the time required to sort the elements. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n .

4. Sort a given set of elements using Selection sort and determine the time required to sort the elements. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n .

5. a. Obtain the topological ordering of vertices in a given digraph.b. Implement All Pair Shortest paths problem using Floyd’s algorithm.

6. Implement the 0/1 knapsack problem using dynamic programming.7. From a given vertex in a weighted connected graph, find shortest paths to other vertices

using Dijkstra’s algorithm.8. Sort a given set of elements using Quick sort method and determine the time required to

sort the elements. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n .

9. Find minimum cost spanning tree of a given undirected graph using Kruskal’s algorithm.10. a. Print all the nodes reachable from a given starting node in a digraph using BFS

method.b. Check whether a graph is connected or not using DFS method.

11. Find a subset of a given set S s1 , s2 ,L, of n positive numbers whose sum is equal to

a given positive number d . For example, if S ,1 ,2 and d 9 , there are solutions ,1 and . A suitable message is to be displayed if the given instance does not have a solution.

12. a. Implement Horspool algorithm for String Matching.b. Find the Binomial Co-efficients using Dynamic Programming.

13. Find the Minimum Cost Spanning Tree of a given undirected graph using Prim’s algorithm.

14. a. Implement Floyd’s algorithm for the All-Pairs-Shortest-Paths problem.b. Compute the transitive closure of a given directed graph using Warshall’s algorithm.

15. Implement n-queens problem using Back tracking.

NOTE: In the examination, questions must be given based on lots.

BNMIT ISE DEPT.

Page 2: 5th Sem ADA Manual

5 th semester ADA lab 2

TUTORIAL: How to determine running-time for iterative and recursive functions, and to plot a graph of running-time versus number of elements.

In programs 1, 2, 3, 4 and 8, it is required to determine running-time of functions used and to plot them as graphs for different values of n . Below is some code and explanation which shows how this is done. These code snippets can then be incorporated into each of the programs1,2,3,4 and 8 by using a switch statement. In these, one case of the switch is for the regular running of the functions on inputs of small sizes and for testing whether they actually work. The other case is for running the functions with large number of inputs, for measuring running-time and for writing this data into files for plotting graphs later. If using a switch statement is undesirable, then the functions whose running-time is to be determined must be included into a separate program and run. This latter method is used here.

When a large number of inputs are given to recursive functions to work on, there is the danger of running out of stack space. This problem is not solved just by increasing the stack size. Therefore, the running-time determination code for recursive functions is slightly different than that of iterative functions. Both are demonstrated here. First, the following example of Bubble sort demonstrates running-time determination for iterative functions. A similar implementation is to be used to determine the running-time of Selection sort and Heap sort routines.

#include <stdio.h>#include <time.h>#include <stdlib.h>#include <values.h>#include <alloc.h>#include <dos.h>

void bubble(int* a, int n){ int i,j,temp;

for(i=0;i<=n-1;i++)for(j=0;j<=n-1;j++){ if (a[i] > a[j])

{ temp = a[i]; a[i]=a[j]; a[j]=temp;

}}

}

void main(){ FILE* fp;

clock_t c1,c2;int i,datasize=1; long int n=1000; int* a;fp=fopen("values.dat","w+");if (fp == NULL){ printf("cannot open file\n");

exit(1);}while(data_size <=10){ a=(int*)calloc(n,sizeof(int));

if (a==NULL){ printf("insufficient memory\n");

exit(1);}

BNMIT ISE DEPT.

Page 3: 5th Sem ADA Manual

5 th semester ADA lab 3

randomize();for(i=0;i<=n-1;i++) a[i]=rand() % MAXINT;c1=clock();bubble(a,n); /*replace this by the iterative function to be evaluated*/c2=clock();free(a);if ((c2-c1) != 0){ fprintf(fp,"%d\t%f\n",n,(c2-c1)/CLK_TCK);

datasize++;

}

}n=n+1000;

}fclose(fp);

In the main function, a file called values.dat (which, by default is created in c:\tc\bin folder) is opened into which the code writes 2 values per line and these values are separated by a single space or more (a tab). The first value is n and the second value is the time in seconds taken by the processor to execute the function whose running-time is to be determined. The value of n starts from 1000 because if n is below that, then the execution time generally clocks zero or very close to zero (this changes from function to function) and this is clumsy to graph. n is incremented by 1000 each time and, totally 10 non-zero running-time values are collected. The file, whose name is specified, is opened in w+ mode, which means that if a file of the same name is already there, then that file is opened for reading and writing and the earlier contents are overwritten. Each line is written into the file using the fprintf function. This file is closed at the end of the main function using fclose function. Functions fopen, fclose and fprintf and the type FILE are defined in the header file stdio.h.

Since the main function is dealing with somewhat large sized arrays, it is efficient to dynamically allocate these arrays. Because of this, the memory model of the C compiler must be changed to `Medium’ to accommodate these large arrays (In the TurboC IDE, go to Options → Compiler → Code generation → Model, and make it `Medium’). The function calloc is used to allocate these arrays dynamically. Correspondingly, the function free is used to deallocate the allocated memory. These functions are defined in the header file alloc.h. A word of caution about arrays of size n allocated by calloc or malloc is that they should be accessed from 0 ton − 1 and not from 1 to n , because otherwise an error called `null pointer assignment’ may be reported by the compiler.

To count the number of seconds elapsed, the number of clock ticks elapsed during the execution of the function whose running-time is to be determined is done as follows. Two variables c1 and c2 of type clock_t are declared, and the function clock is executed just before and just after the calling the function under evaluation. The clock function returns a value of type clock_t, so by subtracting c1 from c2, the number of clock ticks elapsed is obtained. To get the seconds elapsed, the number of clock ticks is divided by the constant CLK_TCK, which gives the number of clock ticks per second. This constant, the function clock and the type clock_t are defined in the header file time.h.

The dynamically allocated array is populated with numbers obtained randomly using the functions randomize and rand. The function rand actually generates the random numbers, and the function randomize re-initializes the seed of the random number generator each time it is executed so as to get different random numbers each time. These functions are defined in the header file stdlib.h.

BNMIT ISE DEPT.

Page 4: 5th Sem ADA Manual

5 th semester ADA lab 4

The file values.dat looks typically as follows after the entries are generated in it, where the first value is the number of elements n and the second value is the time in seconds required to process n elements, in each line.

2000 0.1098903000 0.2197804000 0.4395605000 0.6043966000 0.8791217000 1.1538468000 1.5384629000 1.92307710000 2.41758211000 2.912088

In order to tackle the problem of stack overflow for large sized inputs during the running- time determination of recursive functions, the input problem is subdivided into subproblems of equal size. Each subproblem is solved fully, and then some merging technique is used to obtain the full solution to the given problem. This technique, admittedly, increases the running-time of the code, but keeps the stack use low. The following example of Merge sort demonstrates this.

#include <stdio.h>#include <time.h>#include <stdlib.h>#include <values.h>#include <dos.h>#include <conio.h>#include <malloc.h>

#define SUBPROBSIZE 100

void simplemerge(int* a,int low,int mid,int high){

int *b;int i=low,h=low,j=mid+1,k; b=(int*)calloc(high-low+1,sizeof(int)); if (b == NULL){ printf("insufficient memory for b\n");

exit(1);}while ((h<=mid) && (j<=high)){ if (a[h] <= a[j]) b[i++]=a[h++];

else b[i++]=a[j++];}if (h > mid)

for(k=j;k<=high;k++) b[i++]=a[k];else

for(k=h;k<=mid;k++) b[i++]=a[k];

}

for(k=low;k<=high;k++) a[k]=b[k];free(b);

void mergesort(int* a,int low,int high){ int mid;

if (low<high){ mid=(low+high)/2;

delay(1); /*to increase the running-time a little*/mergesort(a,low,mid);

BNMIT ISE DEPT.

Page 5: 5th Sem ADA Manual

5 th semester ADA lab 5

}}

mergesort(a,mid+1,high);simplemerge(a,low,mid,high);

void main(){ FILE* fp;

clock_t c1,c2; int *a;int i,j,k,m,h,datasize=1,key;long int n=1000;clrscr(); fp=fopen("values.dat","w+"); if (fp == NULL){ printf("cannot open file\n");

exit(0);}while(datasize <=10){ a=(int*)calloc(n,sizeof(int));

if (a == NULL){ printf("insufficient memory for a\n");

exit(1);}randomize();for(i=0;i<=n-1;i++) a[i]= rand() % MAXINT;k=0;c1=clock();for(j=1;j<=n/SUBPROBSIZE;j++){ mergesort(a,k,k+SUBPROBSIZE-1);

k=k+SUBPROBSIZE;}m=SUBPROBSIZE-1; h=2*SUBPROBSIZE-1;while(h<=n){ simplemerge(a,0,m,h);

m+=SUBPROBSIZE; h+=SUBPROBSIZE;

}

} c2=clock(); free(a);fprintf(fp,"%ld\t%f\n",n,(c2-c1)/CLK_TCK);datasize++;n=n+1000;

}fclose(fp);

In the first iteration of the while loop, i.e., for datasize = 1000, the set of input numbers is divided into subproblems each of size SUBPROBLEMSIZE, which is a constant defined at the top of the program using the #define preprocessor directive. This number, typically, is some integer that should be so selected that it is small and the different datasize values should be divisible by this value.

Each subproblem is sent to the subroutine to get solved (in this case, to get sorted). Since the subproblem is solved by recursion, the size of the subproblem, i.e., the value of SUBPROBLEMSIZE, should be small so that stack overflow does not occur. If oveflow occurs anyway (identified by the program crashing or getting stuck unexpectedly), then this value should be reduced to an acceptable value.

BNMIT ISE DEPT.

Page 6: 5th Sem ADA Manual

5 th semester ADA lab 6

Dividing the given problem into subproblems is achieved by the for loop for(j=1;j<=n/SUBPROBSIZE;j++). Sending each subproblem to the recursive function to get solved is achieved by the function call mergesort(a,k,k+SUBPROBSIZE-1). For n=1000 and SUBPROBLEMSIZE = 100 as in the first iteration of the program above, 10 subproblems are created and sent to mergesort function to get separately sorted, i.e., from mergesort(a,0,99) all the way up to mergesort(a,900,999). The solution to the given problem is achieved by merging these piecewise solutions, i.e., by merging all these 10 sorted lists here. There already is a function to do that, called simplemerge, which was implemented to be used by function mergesort for sorting each of the 100 numbers in a subproblem. Using this function, sorted lists a[0]…a[99] and a[100]…a[199] are merged first. Then, sorted lists a[0]…a[199] and a[200]…a[299] are merged, and so on up to a[0]…a[899] and a[900]…a[999]. The time consumed for all these operations is counted by stopping the clock counter after all these operations. Rest of the running-time calculation is identical to that of iterative functions. As before, 10 such data sets are required so as to plot a graph, so each time the number of numbers to be sorted is increased by a 1000 (although other incremental values can be chosen).

It may now be seen as to why the SUBPROBLEMSIZE value must divide the n value exactly. Because if not divided exactly, as in say n = 1000 and SUBPROBLEMSIZE = 120, a subproblem of size less than SUBPROBLEMSIZE is created. In the example here, (1000/120 =) 8.33 subproblems are created. This means, there are 8 subproblems each of size 120, and there are 40 numbers left without being solved at all.

No change is required in the function mergesort to accommodate running-time determination. In the function simplemerge, instead of statically allocating an array b of some suitable size, an array b of size high-low+1 is dynamically allocated and freed so as to make the code more memory-efficient. This code also generates a data file values.dat as done by the iterative version.

The running-time of recursive linear and binary search functions can also be determined using the above technique of creating subproblems. The code snippet for the same in the main

for(j=1;j<=n/SUBPROBSIZE;j++){ i=linsrch(a,k,k+SUBPROBSIZE-1,key);

/*i=binsrch(a,k,k+SUBPROBSIZE-1,key);*/k=k+SUBPROBSIZE;

}/*m=SUBPROBSIZE-1; h=2*SUBPROBSIZE-1;while(h<=n){ simplemerge(a,0,m,h);

m+=SUBPROBSIZE; h+=SUBPROBSIZE;}*/

Searching returns a `yes’ or `no’ as the solution to the subproblem, so merging solutions of subproblems is not really necessary as it consumes hardly any time (if the solution returned from any one of the subproblems is a `yes’, then the search for the key in the entire input set was successful. This involves checking the result of a constant number of subproblems). Hence the merging part in the code above is commented out. The parameters sent to linsrch function have changed slightly. In the code for linsrch working on only a few elements, the parameters sent were a, key and n . But here, a lower limit is also sent, since each subproblem has its own lower and upper limits. The same explanation holds adopting the binary search routine here. When such a technique is used in Quicksort program, simplemerge function must still be used to merge solutions of the subproblems to get the final sorted list.

BNMIT ISE DEPT.

Page 7: 5th Sem ADA Manual

5 th semester ADA lab 7

A graphing program called gnuplot is used to draw a graph on the input set. It is installed in c:\gnuplot and its executable is named as wgnuplot.exe in the folder bin. It is executed by opening a DOS command window, going to the folder where gnuplot is installed, typing wgnuplot.exe and pressing the enter key, as shown in Figure 1. Otherwise, c:\gnuplot\bin can be accessed in Windows explorer and the executable be double-clicked upon.

The window that appears as soon as wgnuplot.exe is executed is shown in Figure 2. gnuplot takes its input from a file in which each x and y coordinate are specified in each line separated by a space or tab. But first, the command called plot needs to be used to tell gnuplot that we need it to plot a graph. This is done by clicking on the menu item Plot as seen in Figure3. When this is done, the word plot comes on the command line of gnuplot. Then, the menu item Data Filename… under Plot must be clicked and gnuplot must be given the file which was created from the above C program. On doing this, the text plot c:\tc\bin\values.dat comes on the command line of gnuplot as seen in Figure 4. Lines are to be drawn through the data points, so plot c:\tc\bin\values.dat with lines is to be typed and enter key must be

Figure 1: Executing gnuplot program

Figures 2 and 3: gnuplot command line and `Plot’ menu

BNMIT ISE DEPT.

Page 8: 5th Sem ADA Manual

5 th semester ADA lab 8

If the x-axis and y-axis labels need to be changed as seen in Figure 6, then the commands set xlabel “input size n” and set ylabel “running-time in seconds” need to be typed before executing the plot command, as seen in Figure 5.

If the running-times of two functions need to be compared on the same graph, assuming that their running-time data files are available at values1.dat and values2.dat, one needs to type plot values1.dat with lines, values2.dat with lines.

Figures 4 and 5: Getting a graph in gnuplot with input from a file, and, setting x- and y- axes labels

Figure 6: Graph drawn by gnuplot with data values from file C:\TC\BIN\values.dat

BNMIT ISE DEPT.

Page 9: 5th Sem ADA Manual

5 th semester ADA lab 9

PROGRAM 1: Implement Recursive Binary search and Linear search and determine the time required to search an element. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n .

#include <stdio.h>#include <conio.h>

int linsrch(int a[],int key,int n){ if (n == 0) return 0;

if (a[n] == key) return n;else return linsrch(a,key,n-1);

}

int binsrch(int a[],int key,int low, int high){ int mid;

if (low>high) return 0;else{ mid=(low+high)/2;

if (a[mid] == key) return mid;else if (a[mid] < key) return binsrch(a,key,mid+1,high);else return binsrch(a,key,low,mid-1);

}}

void main(){ int n,ch,i,a[10],key,flag;

char ok='y';clrscr();while (ok !='n' || ok !='N'){ printf("enter number of numbers to search in\n");

scanf("%d",&n);printf("enter key to search\n");scanf("%d",&key);printf("1:Recursive linear search\n2:Recursive binary search\n");printf("any other key to exit\n"); printf("enter your choice\n"); scanf("%d",&ch);switch(ch){ case 1: printf("enter numbers in any order\n");

for(i=1;i<=n;i++) scanf("%d",&a[i]); flag=0;flag=linsrch(a,key,n);if (flag != 0) printf("search key found at position

%d\n",flag);

%d\n",flag);

}

else printf("search key not found\n");break;

case 2: printf("enter numbers in ascending order\n");for(i=1;i<=n;i++) scanf("%d",&a[i]);flag=0;flag=binsrch(a,key,1,n);if (flag != 0) printf("search key found at position

else printf("search key not found\n");break;

default : break;

printf("press y or Y to continue, n or N to quit\n");fflush(stdin);

BNMIT ISE DEPT.

Page 10: 5th Sem ADA Manual

5 th semester ADA lab 10

}}

ok=getc(stdin);if (ok =='y' || ok == 'Y') continue;else exit();

The function linsrch, which does linear search, is an example for Brute force technique. The recursion checks each item with the key. It is convenient to search from n down to 1 instead of going from 1 to n, since n is being passed to the function in the call from the main function. Recursion stops when n reaches 0 as we have entered data from a[1] and not from a[0]. Thismeans the function did not find the key and the search is a failure. The running-time issince all n elements are compared with the key.

O(n)

The function binsrch, which does binary search on a list of elements sorted in ascending order, is an example for Divide and conquer strategy. The list of elements is split into two halves each time by computing a mid value. This is the divide step. The key being searched for is compared with a[mid], and if the values are equal, the search is a success. This is the conquer step. If not, then if the key is smaller than a[mid], it is searched for in the lower half of the list, and the upper half of the list is discarded. If the key is larger than a[mid], it is searched for in the upper half of the list, and the lower half of the list is discarded. This goes on till the subproblem size reduces to 1 and recursion stops here (because low = high at this point, and low, high and mid all point to the same element) after checking that single element whether it is equal to the search key. If not, then the search is a failure.

Based on this, the recurrence relation for binary search can be written asT (n) 1.T (n / 2) O( )1 . The divisor 2 in T (n / 2) signifies that the problem is halved each The multiplier 1 beside T (n / signifies that of the two subproblems created, only one of themneeds to be solved (upper half or lower half). The O( in the equation signifies that to divide theproblem and to check whether the element a[mid] is equal to the search key, it takes O( time.

There is no need for any merge step here. On solving this recurrence using Master theorem or backward substitution, we get the running-time of binary search as O(log n) .

BNMIT ISE DEPT.

Page 11: 5th Sem ADA Manual

5 th semester ADA lab 11

PROGRAM 2: Sort a given set of elements using the Heapsort method and determine the time required to sort the elements. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n .

#include <stdio.h>#include <conio.h>

void heapify(int a[], int n){ int i,j,k,item;

for(k=2;k<=n;k++){ item = a[k];

i=k, j=i/2;while ((i>1) && (item > a[j])){ a[i] = a[j];

i=j, j=i/2;

}}

}a[i]=item;

void adjust(int a[], int n){ int i,j,item;

j=1, item=a[j], i=2*j;while (i <= n){ if ((i+1 <= n) && (a[i] < a[i+1])) ++i;

if (item < a[i]){ a[j] = a[i];

j=i, i=2*j;

}

}else break;

}a[j]=item;

void heapsort(int a[],int n){ int i,temp;

heapify(a,n); for(i=n;i>1;i--){ temp = a[i];

a[i] = a[1]; a[1] = temp; adjust(a,i-1);

}}

void main(){ int n,i,a[10];

clrscr();printf("enter number of numbers to be sorted\n");scanf("%d",&n);printf("enter numbers to be sorted\n"); for(i=1;i<=n;i++) scanf("%d",&a[i]); heapsort(a,n);printf("the sorted list is\n"); for(i=1;i<=n;i++) printf("%d\n",a[i]); getch();

}

BNMIT ISE DEPT.

Page 12: 5th Sem ADA Manual

5 th semester ADA lab 12

This problem is an example for Transform and Conquer strategy. To sort a set of numbers, the set is transformed into a heap, and then conquered.

This code sorts numbers in ascending order. For this reason, a max-heap is implemented here. A max-heap has the following properties: a) the parent is larger than both its children, b) the elements are filled into a heap from left to right, and, c) if a parent’s number is i, its left child can be accessed by 2i and its right child by 2i+1. (Only property a) changes for a min-heap.)

In each step of heap sort, a max-heap is created, because of which the largest element comes to the top of the heap. Then, this element is exchanged with the last element of the heap(this last element need not be the smallest element of the list). The heap is implemented in an array, so the largest element comes to its final resting position (in the sorted list) and is not considered anymore for sorting. This functionality is implemented in the function heapsort.

The function heapsort, which is called from the main function, has two functions, heapify and adjust. The function heapify takes an array of numbers and makes a max-heap out of the list by using the top-down heap creation technique. It starts from the second element(left child of the root), compares it with its parent and, if found to be greater than its parent, moves it to the top. In general, for some child a[k], its parent being a[k/2], if a[k/2] is smaller than a[k], then they are exchanged. This exchange may propagate all the way up to the the heap. This function has a running-time ofthe sorting process starts.

O(n log and is performed only once, just before

Once a heap is created, the largest element comes to the top of the heap, which is then exchanged with the last element. Because of this exchange, the data structure is no longer a max- heap. Only one path from the root level to the leaf level needs to be examined and adjusted to restore max-heap property. To accomplish this, the function adjust examines a parent and its two children each time from top to bottom and exchanges the elements as required. This function takes O(log n) time as the height of the heap (which is also a balanced binary tree) is O(log n) .

A note: The program will work correctly even if, in the function heapsort, function call adjust(a,i-1) is replaced with heapify(a,i-1). That is, the function adjust is not required at all. But then this implies that, each time a root and last elements are exchanged and max-heap property is to be restored, we have to call function heapify. Since there are n elements in total,calling heapify n times will make Heap sort run in O(n2 log n) time. But by using functionadjust to restore heap property, we need to call it n times, so running-time becomes O(n log n) .

BNMIT ISE DEPT.

Page 13: 5th Sem ADA Manual

5 th semester ADA lab 13

PROGRAM 3: Sort a given set of elements using Merge sort method and determine the time required to sort the elements. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n .

#include <stdio.h>#include <conio.h>

void simplemerge(int a[],int low,int mid,int high){ int b[10],i=low,h=low,j=mid+1,k;

while ((h<=mid) && (j<=high)){ if (a[h] <= a[j]) b[i++]=a[h++];

else b[i++]=a[j++];}if (h > mid)

for(k=j;k<=high;k++) b[i++]=a[k];else

for(k=h;k<=mid;k++) b[i++]=a[k];

}for(k=low;k<=high;k++) a[k]=b[k];

void mergesort(int a[],int low,int high){ int mid;

if (low<high){ mid=(low+high)/2;

mergesort(a,low,mid); mergesort(a,mid+1,high); simplemerge(a,low,mid,high);

}}

void main(){ int n,i,a[10];

clrscr();printf("enter number of numbers to sort\n");scanf("%d",&n);printf("enter the numbers to sort\n"); for (i=1;i<=n;i++) scanf("%d",&a[i]); mergesort(a,1,n);printf("the sorted list of numbers are\n"); for (i=1;i<=n;i++) printf("%d\n",a[i]); getch();

}

This is a problem in Divide and conquer. Like in Binary search, the list of numbers is halved every time, but unlike binary search, no part of the list can be discarded, since we have to sort all the numbers.

The function mergesort divides the list of numbers recursively into 2 parts, one from low to mid and another from mid+1 to high. This is the divide step. The merging step happens in the function simplemerge. It merges two sorted lists, one from low to mid and another from mid+1 to high, and this is the conquer step. It first compares the first elements in both lists. If the first element of the first list is smaller than the first element of the second list, then the first few elements of the first list is copied into a third list till a number is found in the first list which is larger than the first element of the second list. Vice-versa if the first element of smaller than the first element of the first list. As each list issimplemerge is O(n) .

O(n) in size, the running-time of

BNMIT ISE DEPT.

Page 14: 5th Sem ADA Manual

5 th semester ADA lab 14

Alternating copying of elements from both lists may end up in one of the lists getting completely copied into the third list earlier than the other list. This happens when the list are not equal in size (but their size will both be O(n) ). When this happens, the contents of the remaining list are simply copied into the third list. The rest of the program does not know of the existence of the third list, so at the end of simplemerge, this third list contents are overwritten onto the original list itself.

Based on this, the recurrence relation for merge sort can be written asT (n) 2T (n / 2) O(n) . The divisor 2 in T (n / signifies that the problem is halved each time.The multiplier 2 beside T (n / 2) signifies that both the subproblems created by the divide step areto be solved. The O(n) signifies that to divide a problem into subproblems, to solve individualsubproblems and to merge their individual solutions, it takes O(n) time. On solving thisrecurrence relation using Master theorem or backward substitution, we get

O(n log as

BNMIT ISE DEPT.

Page 15: 5th Sem ADA Manual

5 th semester ADA lab 15

PROGRAM 4: Sort a given set of elements using Selection sort and determine the time required to sort the elements. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n .

#include <stdio.h>#include <conio.h>

void selsort(int a[],int n){ int i,j,small,temp;

for(i=1;i<=n-1;i++){ small=i;

for(j=i+1;j<=n;j++)if (a[j] <= a[i]) small=j;

temp=a[i]; a[i]=a[small]; a[small]=temp;

}}

void main(){ int i,n,a[10];

clrscr();printf("enter number of numbers to sort\n");scanf("%d",&n);printf("enter numbers to sort\n"); for(i=1;i<=n;i++) scanf("%d",&a[i]); selsort(a,n);printf("sorted list is\n"); for(i=1;i<=n;i++) printf("%d\n",a[i]); getch();

}

This problem falls under the Brute force strategy. The idea is to scan the given array to find out the smallest element, and once found, it is exchanged with the first element. Then, the remainder of the array is scanned to find the next smallest element, and once found it is exchanged with the second element. This is done till the (n − )1 th element.

To find the smallest element for the first time, it n comparisons. To find second smallest element, it n − comparisons. To find (n − )1 th smallest element, takes 1 comparison. On adding all these numbers of comparisons, we get1 2 3 L (n − 2) which solves to O(n2 ) .

BNMIT ISE DEPT.

Page 16: 5th Sem ADA Manual

5 th semester ADA lab 16

PROGRAM 5a: Obtain the topological ordering of vertices in a given digraph.

#include <stdio.h>#include <conio.h>

struct stack{ int content[20],top;}s;

void push (int i){ s.content[++(s.top)] = i;}

int pop (){ return s.content[(s.top)--];}

int is_empty (){ if (s.top == -1) return 1;

return 0;}

void topo_order(int adjm[][10], int to[], int n){ int i,j,k=1,in[10],deg;

s.top=-1; for(i=1;i<=n;i++){ deg=0;

for(j=1;j<=n;j++) if (adjm[j][i] == 1) deg++;in[i]=deg;

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

if (in[i] == 0){ push(i);

in[i]--;

}

}if (is_empty()) break;to[k]=pop();for(i=1;i<=n;i++) if (adjm[to[k]][i] == 1) in[i]--;k++;

if (k<n){ printf("topological sorting not possible\n");

exit();

}}

void main(){ int n,adjm[10][10],i,j,to[10];

clrscr();printf("enter the number of vertices in the DAG for topological

sort\n");scanf("%d",&n);printf("enter the adjacency matrix of the DAG\n");for(i=1;i<=n;i++)

for(j=1;j<=n;j++)scanf("%d",&adjm[i][j]);

topo_order(adjm,to,n);printf("the topological ordering of the vertices in entered DAG is\n");

BNMIT ISE DEPT.

Page 17: 5th Sem ADA Manual

5 th semester ADA lab 17

}

for(i=1;i<=n;i++) printf("%d ",to[i]);getch();

Topological sort is done on directed graphs and can be done in two different ways. One is by vertex removal. In this method, a vertex which has no in-edges (i.e., it has only out-edges) is found and is deleted along with all its out-edges. The order in which these vertices are deleted is kept track of, and when there are no more vertices to delete, the previously mentioned order is reversed and displayed.

The other method is by DFS. This method starts off by doing DFS on the given digraph. The order in which these vertices become dead ends is kept track of, and then when there is nowhere else for the DFS to visit, the previously mentioned order is reversed and displayed.

It is obvious from the above description that, no matter which method is used, it is convenient to implement a stack, so that reversing the order in which vertices were inserted into the stack is easy. The first method is implemented in the code here. A structure called stack is created, which has a pointer called top to the topmost element of the stack.

The number of in-edges to a vertex is counted and stored in an array called in. So, in[i] gives the number of in-edges to vertex i. The cycle starts by searching for some vertices in the given digraph which has no in-edges, i.e., in[i] is 0 for such vertices (In the first cycle of the infinite for loop, this happens even without having to delete any vertex). If there are, they are searched for in the array in and pushed onto the stack. Once all such vertices are found, they are entries of such vertices in the array in are made − so that they are not counted again in thenext iteration, hence effectively deleting them. Having done so, the edges going out of them also cease to exist, so that the in-degree of those vertices to which these out-going edges point to are reduced by 1.

The program ends when there are no more items on the stack. Integer k keeps track of how many vertices were pushed/popped onto/from the stack. If k < n, then all the vertices in the graph were not pushed/popped, which means that the in array’s entry for such vertices never became 0. This implies that there is a cycle in the entered digraph. But, as topological sort is defined for acyclic graphs, the program prints that there is no solution.

Reading the adjacency matrix takes O(n2 ) time. To find one vertex with zero in-edges,

we scan the in array entries of all n vertices, so this takes O(n) , hence O(n2 ) for all vertices.

On the whole, the running-time of this implementation is O(n2 ) .

BNMIT ISE DEPT.

Page 18: 5th Sem ADA Manual

5 th semester ADA lab 18

PROGRAM 5b: Implement All Pair Shortest paths problem using Floyd’s algorithm.

#include <stdio.h>#include <conio.h>

int min(int a,int b){ return (a<b)?a:b;}

void floyd(int cost[][10], int n){ int i,j,k;

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

for(j=1;j<=n;j++)cost[i][j] = min(cost[i][j], cost[i]

[k]+cost[k][j]);}

void main(){ int n, i,j,cost[10][10];

clrscr();printf("enter the number of vertices\n");scanf("%d",&n);printf("enter the cost matrix of graph, with 999 for infinity\n");for(i=1;i<=n;i++)

for(j=1;j<=n;j++)scanf("%d", &cost[i][j]);

floyd(cost,n);printf("the shortest distance matrix from all to all vertices are\n");for(i=1;i<=n;i++){ for(j=1;j<=n;j++)

printf("%d ",cost[i][j]);printf("\n");

}

}getch();

In graphs, if the shortest paths from vertex a to b and b to c are known, then the shortest path from a to c is known. So, getting the shortest path from a to c requires solving two subproblems. Now, if the shortest path from a to d is required, and c is connected to d by an edge, then it is required to solve the shortest path queries from a to b, b to c and c to d. Here, finding shortest paths from a to b and from b to c are common subproblems to both above problems, and need not be solved again and again, but can be stored in a table. This is why Floyd’s algorithm is an example for the dynamic programming technique.

To actually compute the shortest paths between two vertices, Floyd’s algorithm considers a pair of vertices u and v at a time and all other vertices as intermediate vertices through whichthe shortest path between u and v might be passing. This check O(n) time per pair

vertices. There are

O(n3 ) .

O(n2 ) pair of vertices, so the overall running-time for this algorithm is

BNMIT ISE DEPT.

Page 19: 5th Sem ADA Manual

5 th semester ADA lab 19

PROGRAM 6: Implement the 0/1 knapsack problem using dynamic programming.

#include <stdio.h>#include <conio.h>

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

int MFknapsack(int i, int j, int p[], int w[], int v[][11]){ int value;

if (v[i][j] < 0){ if (j< w[i]) value = MFknapsack(i-1,j,p,w,v);

elsevalue = max(MFknapsack(i-1,j,p,w,v), p[i]

+MFknapsack(i-1,j-w[i],p,w,v));

}v[i][j]=value;

}return v[i][j];

void main(){ int n,i,j,p[10],w[10],v[11][11],val,C;

clrscr();printf("enter number of objects\n");scanf("%d",&n);printf("enter the capacity of the knapsack\n");scanf("%d",&C);printf("enter the profit of each of %d objects\n",n);for(i=1;i<=n;i++) scanf("%d",&p[i]);printf("enter the weight of each of %d objects\n",n);for(i=1;i<=n;i++) scanf("%d",&w[i]);for(i=0;i<=n;i++)

for(j=0;j<=C;j++)if ((i==0) || (j==0)) v[i][j]=0;else v[i][j]=-1;

val=MFknapsack(n,C,p,w,v);printf("the total value of the objects in the knapsack is: %d\n",val);printf("the objects picked up into the sack are: ");i=n, j=C;while (i>0){ if (v[i][j] != v[i-1][j])

{ printf("%d ",i);j=j-w[i], i--;

}

}else i--;

}getch();

A knapsack of capacity C and n items, each with profit p[i] and weight w[i], are given. Some subset of the n items is to be placed into the knapsack so that the total value of items in the knapsack is maximized while not exceeding the capacity of the knapsack.

This problem can be solved in 3 ways: top-down method, bottom-up dynamic programming method and memory function dynamic programming method. The top-down approach is done as follows: to solve the problem of placing a i -sized subset of n knapsack while maximizing the value, one has to solve the problem of placing i − sized

BNMIT ISE DEPT.

Page 20: 5th Sem ADA Manual

5 th semester ADA lab 20

subset of n items in the knapsack while maximizing the value. The i − item may be placed ornot. The subproblems need to be kept track of, and there might be repeated/overlapping subproblems to solve. This takes exponential time, and the running-time analysis is similar to that of generating Fibonacci numbers using top-down approach.

A good idea is to use a table to keep track of the subproblems. A 2D array v is used to dothis, i.e., what is the value of the items in the knapsack if the ith item is put into it, or what is thevalue if the ith item is not put into it. If there are repeated subproblems, they are solved onlyonce and stored into the corresponding entry in array v, and this value is simply used whenever the same subproblem arises again. The table size will simply be nC and all values in the table have to be computed. Column and row 0 are initialized to 0. This is because v[k][0] = 0 means that the kth item is the first one to be considered and the knapsack is empty, so there is no value. Conversely, v[0][k] = 0 means that if no item is considered but the knapsack is considered tobe k full, still the knapsack is empty and there is no value. Among O(nC )correspond to infeasible placements, so computing all nC entries is overkill.

entries, many entries

Yet another idea is to combine both top-down approach and bottom-up dynamic programming approach. The solution starts by considering the problem of placing n objects inthe C -sized knapsack, and corresponding value in the table v[n][C] is made − to representthis fact. Two subproblems are generated from this, i.e., the problem of placing the n − objector the problem of not placing the n − object. Because of this, all the elements in the n − row of the table v are not computed. So, all nC values are not computed using this approach, which makes it the most efficient approach among the three approaches.

All values of the 2D array v are initialized to -1, except values in the 0th column and values in the 0th row (which are made 0) and the MFknapsack function is called. The function checks whether the entry v[i][j] is -1 (by checking whether v[i][j] < 0), and if so, it goes ahead to compute it. If v[i][j] is not -1, then it indicates that this value has already been computed, and therefore is not computed again but its value is just used. This happens recursively and the very first value for which this check happens is for v[n][C].

max(The equation [v i][ j ]

[v − ] j], i [v − ] j − i ]) if j − i ≥

[v i − ]1 if j −

that has been derived in the Levitin book (Page 295, Eq 8.12), has been used here recursively, i.e., v[i-1][j] and v[i-1][j-w[i]] are computed recursively only if not computed before. The value of v[n][C] is returned to the main program.

The program also has to say which are the items actually put into the knapsack so as to get the optimal solution. The code starts by looking at the value v[n][C]. It compares this withv[n-1][C] and if these values are same, then the ith item was not picked up since there was notenough space in the knapsack. If not same, then the ith item was picked up, and the code resumesearching for other picked items from v[n-1][C-w[i]], since the knapsack now has the ith

and its remaining capacity is only C-w[i].item

size.The running-time of this code is O(nC ) , since the code has to populate the table of that

BNMIT ISE DEPT.

Page 21: 5th Sem ADA Manual

5 th semester ADA lab 21

PROGRAM 7: From a given vertex in a weighted connected graph, find shortest paths to other vertices using Dijkstra’s algorithm.

#include <stdio.h>#include <conio.h>

void dijkstra(int src, int cost[][10], int dist[], int n){

int visited[10],min,i,j,u;for(i=1;i<=n;i++){ visited[i]=0;

dist[i]=cost[src][i];}visited[src]=1, dist[src]=0;for(i=1;i<=n;i++){ if (i == src) continue;

min=999; for(j=1;j<=n;j++)

if ((visited[j] == 0) && (min > dist[j])){ min=dist[j];

u=j;}

visited[u]=1; for(j=1;j<=n;j++)

if(visited[j] == 0){ if(dist[j] > dist[u] + cost[u][j])

dist[j] = dist[u]+cost[u][j];

}}

}

void main(){ int n,cost[10][10],dist[10]={0},i,j,src;

clrscr();printf("enter number of vertices in the graph\n");scanf("%d",&n);printf("enter the adjacency matrix of the graph, with 999 for

infinity\n");for(i=1;i<=n;i++)

for(j=1;j<=n;j++)scanf("%d",&cost[i][j]);

printf("enter the source vertex\n"); scanf("%d",&src); dijkstra(src,cost,dist,n);printf("the shortest paths from src %d to all other vertices

are\n",src);for(i=1;i<=n;i++) printf("to %d = %d\n",i,dist[i]);getch();

}

This problem, also called Single source shortest path, is an example for Greedy technique. The function dijkstra starts at a source vertex, which is passed to this function from the main function. A vector called dist[i], which represents the distance from source vertex to vertex i, is initialized using the cost matrix from the main function. A vector called visited[i] stores either 1 or 0, where 1 implies that vertex i has been visited and its shortest path from source vertex has already been computed.

BNMIT ISE DEPT.

Page 22: 5th Sem ADA Manual

5 th semester ADA lab 22

Using the dist vector, the vertex that is closest to the source vertex is found, by being greedy. Using this vertex, it is checked to see whether any other vertices can come closer to the source vertex. In this way, at program termination, the shortest distance from the source to all other vertices is got.

This code runs in O(n2 ) time because the cost matrix which is to be read has size O(n2 )and there are two for loops in the dijkstra function.

BNMIT ISE DEPT.

Page 23: 5th Sem ADA Manual

5 th semester ADA lab 23

PROGRAM 8: Sort a given set of elements using Quick sort method and determine the time required to sort the elements. Repeat the experiment for different values of n , the number of elements in the list to be searched and plot a graph of the time taken versus n .

#include <stdio.h>#include <conio.h>

int partition(int a[],int low, int high){ int pivot,i,j,temp;

pivot=a[low], i=low, j=high; while (i<j){ while ((a[i]<= pivot) && (i<= high)) i++;

while ((a[j]> pivot) && (j>= low)) j--;if (i<j){ temp=a[i];

a[i]=a[j]; a[j]=temp;

}}

}

temp=a[j]; a[j]=a[low]; a[low]=temp; return j;

void quicksort(int a[], int low, int high){ int j;

if (low<high){ j=partition(a,low,high);

quicksort(a,low,j-1); quicksort(a,j+1,high);

}}

void main(){ int i,n,a[10];

clrscr();printf("enter the number of numbers to sort\n");scanf("%d",&n);printf("enter the numbers to sort\n"); for(i=1;i<=n;i++) scanf("%d",&a[i]); quicksort(a,1,n);printf("the sorted list is\n"); for(i=1;i<=n;i++) printf("%d\n",a[i]); getch();

}

This problem is an example under Divide and Conquer strategy. In the general Quicksort, a pivot element is selected by some strategy. In this code here, the first element of the array sent to the (sub)problem is selected as pivot and also as a[low], and the last element as a[high]. Two variables i and j are initialized to low and high respectively. As long as pivot is greater that a[i], i is incremented. As long as pivot is smaller than a[j], j is decremented. Once i and j stop incrementing and decrementing respectively, they are compared with each other. If i<j, then a[i] and a[j] are exchanged and comparisons of pivot with a[i] and a[j] are continued as before. If not, then a[j] is exchanged with pivot element. This divides the array between low and high into 2 parts, i.e., elements smaller than pivot to the left and elements greater than

Page 24: 5th Sem ADA Manual

5 th semester ADA lab 24

pivot to the right. The pivot itself is put into the correct sorted position, so it is not touched again. This creates two subproblems, one with elements from low to the position previous to the sorted pivot element position, and, another one with elements from position next to the sorted pivot element position to high.

Finding the sorted pivot element position is done by function partition. Dividing the array into two parts based on the sorted pivot element position is done by function quicksort recursively.

The performance of Quicksort depends on the selection of the pivot element. A well- selected pivot element divides the problem into roughly two halves, because of which the performance of Quicksort is similar to that of Merge sort, i.e., O(n log n) . A badly selected pivot element divides the array into two parts, where the number of elements on one side is too small when compared to that on the other side. In the technique used here, selecting a[low] as pivot performs very badly when the array is already (or almost) sorted, either in increasing or decreasing order, because it divides an array of size n into an array of size 1 and an array of sizen − 1. In this case, Quick sort executes in O(n2 ) time, just like Insertion sort.

BNMIT ISE DEPT.

Page 25: 5th Sem ADA Manual

5 th semester ADA lab 25

PROGRAM 9: Find minimum cost spanning tree of a given undirected graph using Kruskal’s algorithm.

#include <stdio.h>#include <conio.h>

void kruskal(int cost[][10], int n, int mst[][10]){ int min_edge_weight=999,u,v,i,j,k,l,parent[10],edges=0,temp;

for(i=1;i<=n;i++){ cost[i][i]=999;

for(j=1;j<=n;j++)if ((j>i) && (cost[i][j] != 999)) edges++;

}for(i=1;i<=n;i++) parent[i]=i;while (edges != 0){ for(i=1;i<=n;i++)

for(j=1;j<=n;j++)if ((j>i) && (cost[i][j] < min_edge_weight)){ min_edge_weight=cost[i][j];

u=i, v=j;}

i=parent[u], j=parent[v];if (i != j){ mst[u][v]=mst[v][u]=cost[u][v];

if (i<j){ for(k=1;k<=n;k++)

if (parent[k] == j) parent[k]=i;}else{ for(k=1;k<=n;k++)

if (parent[k] == i) parent[k]=j;

}}

}}

cost[u][v]=cost[v][u]=999; edges--; min_edge_weight=999;

void main(){ int i,j,n,cost[10][10],mst[10][10]={0},total=0;

clrscr();printf("enter number of vertices in the undirected graph\n");scanf("%d",&n);printf("enter the cost matrix of the graph, with 999 for no edges\n");for(i=1;i<=n;i++)

for(j=1;j<=n;j++)scanf("%d",&cost[i][j]);

kruskal(cost,n,mst);printf("a MST for the given graph is\n");for(i=1;i<=n;i++)

for(j=1;j<=n;j++)if ((j>i) && (mst[i][j] != 0)){ printf("%d - %d\n",i,j);

total=total+mst[i][j];}

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

BNMIT ISE DEPT.

Page 26: 5th Sem ADA Manual

5 th semester ADA lab 26

}

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

}

printf("the total cost of this MST is %d\n",total);getch();

This is a problem that falls into the Greedy technique category. In the Kruskal’s algorithm, the edges are first sorted in ascending order of their weights. Each edge is considered in the sorted order. An edge is added to the growing MST if introducing that edge does not create a cycle. The algorithm stops when all the edges have been considered.

In the function kruskal here, instead of actually creating an edge list and sorting them based on their weights, the minimum cost edge is found out each time by going through the entire cost matrix. This is inefficient as far as the running-time is concerned, but it simplifies the code quite a bit. To find the minimum cost edge using the cost matrix, cost[i][i] is first made infinity (here, infinity is taken as 999). This is because, for graphs whose vertices do not have self loops, the cost[i][i] is always 0, and if this is not made infinity, edge i-i will be reported as the minimum cost edge each time.

The function kruskal stops after considering all edges for inclusion into the MST, so the number of edges needs to be determined so as to serve as an upper limit to the number of times the main for-loop is executed. The input being an undirected graph, the entries will be identical for cost[i][j] and cost[j][i], so only one of these should be considered for counting the number of edges. Only cost matrix entries which are not infinity should be counted, since those with infinity represent the lack of edges between corresponding vertices.

The function next finds the currently smallest edge by looking at all the entries of the cost matrix. The two vertices of this lowest cost edge are stored in u and v. Then, it is

checked whether the parent vertices of u and v are the same (this is explained later). If they are, then a cycle will be created by introducing edge u-v into the MST, and hence edge

u-v is not introduced. If parents of u and v are not same, then it is fine to introduce edge u-v into the MST. After considering this edge u-v, the entry cost[u][v] or cost[v][u] must not be included in further considerations, therefore its entry is made 999. Since this particular edge

hasbeen considered, the number of edges decreases by 1.

Regarding comparing parents of vertices: a vector called parent is kept so that parent[i] gives the parent of vertex i. In the beginning of function kruskal, each vertex is initialized as its own parent. Now, somewhere during the execution of the function, the following scenario occurs. Vertex u is connected to some subtree of the future MST, and vertex v is connected to another subtree of the future MST. Let these two subtrees to not have any vertices in common (i.e., let them be disjoint, this is allowed in Kruskal’s algorithm, but not in Prim’s algorithm), because if they do, then the edge u-v cannot be added to the MST. On adding this edge, the two previously disjoint subtrees join to become a big tree. All the vertices in this new tree must now be made to have the same parent. This new parent must be the parent of either u or v. To break this tie, if the parent of u is numerically smaller than the parent of v, then the parent of all vertices in the new tree is made as u. Viceversa if parent of v is numerically smaller than the parent of u.

The MST itself is represented by a 2D array called mst. Once an edge u-v is introduced into the MST successfully, array elements mst[u][v] and mst[v][u] are made equal to cost[u][v]. Scanning this matrix fully will give all edges of the MST, and adding only non-

BNMIT ISE DEPT.

Page 27: 5th Sem ADA Manual

5 th semester ADA lab 27

This implementation executes in O(n4 ) time. The cost matrix, which is input, is of size

O(n2 ) . Counting the number of edges in the graph O(n2 ) time, since the entries in

upper/lower half of the cost matrix, of size roughly n2 / 2 , has to be considered. Each time thesmallest edge is to be determined, these n2 / entries are looked at. There can be at most n2 / edges, so the overall running-time is roughly n4 / 4 , which is O(n4 ) .

BNMIT ISE DEPT.

Page 28: 5th Sem ADA Manual

5 th semester ADA lab 28

PROGRAM 10a: Print all the nodes reachable from a given starting node in a digraph usingBFS method.

#include <stdio.h>#include <conio.h>

void insertq(int q[], int node, int* f, int* r){

}

if ((*f==-1) && (*r==-1)){ (*f)++, (*r)++, q[*f]=node;}else{ (*r)++, q[*r]=node;}

int deleteq(int q[], int* f, int* r){ int temp;

temp=q[*f];if (*f==*r) *f=*r=-1;else (*f)++;return temp;

}

void bfs(int n, int adj[][10], int src, int visited[]){ int q[20],f=-1,r=-1,v,i;

insertq(q,src,&f,&r);while ((f <= r) && (f != -1)){ v=deleteq(q,&f,&r);

if (visited[v]!=1){ visited[v]=1;

printf("%d ",v);

}}

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

if ((adj[v][i] == 1) && (visited[i] != 1))insertq(q,i,&f,&r);

void main(){ int n,i,j,adj[10][10],src,visited[10];

clrscr();printf("enter number of vertices\n");scanf("%d",&n);printf("enter the adjacency matrix of the digraph for BFS\n");for(i=1;i<=n;i++){ visited[i]=0;

for(j=1;j<=n;j++)scanf("%d",&adj[i][j]);

}

}printf("enter starting vertex\n");scanf("%d",&src);printf("the nodes reachable from src are\n");bfs(n,adj,src,visited);getch();

This problem is an example for Decrease and conquer, i.e., when each vertex is visited,the number of vertices to be visited decreases by one.

BNMIT ISE DEPT.

Page 29: 5th Sem ADA Manual

5 th semester ADA lab 29

A simple queue is implemented here, with insertion from rear and deletion from front. A vertex i is first deleted from the queue, visited by the function bfs (i.e., visited[i] is made 1), and all its unvisited neighbors are inserted into the queue at the rear. This way, the function bfs visits all vertices in the graph in a `as wide as possible’ manner. As and when the function bfs visits a vertex, it is printed out. If all the vertices in the graph are not printed out, it does not necessarily mean that the graph is disconnected. It may only mean that there are no in-edges going into (but only out-edges coming out of) the vertices that have not been printed.

The running-time of this code isbeen used.

O(n2 ) because an adjacency matrix of size O(n2 ) has

BNMIT ISE DEPT.

Page 30: 5th Sem ADA Manual

5 th semester ADA lab 30

PROGRAM 10b: Check whether a graph is connected or not using DFS method.

#include <stdio.h>#include <conio.h>

void dfs(int adjm[][10],int visited[],int n, int src){ int w;

visited[src]=1; for(w=1;w<=n;w++){ if ((adjm[src][w] == 1) && (visited[w] == 0))

{ printf("%d -- %d\n",src,w);dfs(adjm,visited,n,w);

}}

}

void main(){ int n,i,j,adjm[10][10],src,visited[10]={0},flag,p;

clrscr();printf("enter number of nodes for the undirected graph for DFS\n");scanf("%d",&n);printf("enter the adjacency matrix\n");for(i=1;i<=n;i++)

for(j=1;j<=n;j++)scanf("%d",&adjm[i][j]);

printf("enter source vertex from where to start DFS\n");scanf("%d",&src); dfs(adjm,visited,n,src); for(i=1;i<=n;i++)if (visited[i] != 1) flag=1, p=i;if (flag == 1) printf("the node %d is isolated and graph is

unconnected\n",p);else printf("the graph is connected\n");getch();

}

This is a problem under Decrease and Conquer. The strategy is to visit one vertex at a time, because of which the number of vertices to be visited reduces by 1.

The dfs function moves from one vertex to another vertex if there is an edge between the two vertices. When the dfs function visits a vertex x, visited[x] is made 1. If the graph is connected, then the dfs function is able to visit all the vertices. On checking the visited array to see whether all the vertices are visited, if the main function sees that some vertex is unvisited(i.e., if visited[x] = 0 for some x), the graph is reported to be disconnected.

Recursion is ideally suited to implement DFS. Take any recursive function and draw a tree whose nodes represent every stage of execution of the recursive function. Now, if DFS is done on this tree, it can be seen that the DFS ordering is identical to the way in which

The running-time of this code isbeen used.

O(n2 ) because an adjacency matrix of size O(n2 ) has

BNMIT ISE DEPT.

Page 31: 5th Sem ADA Manual

5 th semester ADA lab 31

PROGRAM 11: Find a subset of a given set S s1 , s2 ,L, of n positive numbers whose sum

is equal to a given positive number d . For example, S ,1 ,2 and d 9 , there are solutions ,1 and . A suitable message is to be displayed if the given problem instancedoes not have a solution.

#include <stdio.h>#include <conio.h>

int is_even(int i){ return (i%2 == 0)?1:0;}

int power(int x,int y){ int i,res=1; for(i=1;i<=y;i+

+) res=res*x; return res;

}

int sos(int n, int s[], int d){ int sst[100],i,j,flag,k=1,h;

sst[k]=0, k++,flag=1; for(i=1;i<=n;i++){ for(j=1;j<=power(2,i);j++)

{ if (flag==1){ sst[k]=sst[(k/2)]+s[i];

flag=0, k++;}else{ sst[k]= sst[(k/2)];

flag=1, k++;

}}

}

flag=0;for(i=power(2,n); i<=(power(2,n+1)-1);i++){ j=i, h=n;

if (sst[j] == d){ flag=1;

while(h>0){ if (is_even(j))

{ printf("%d ",s[h]);j=j/2, h--;

}

}else{ j=j/2, h--;}

}}

printf("\n");

}return flag;

void main(){ int i,n,s[10],d,flag;

clrscr();printf("enter number of numbers\n");

BNMIT ISE DEPT.

Page 32: 5th Sem ADA Manual

5 th semester ADA lab 32

}

scanf("%d",&n);printf("enter the set S of %d numbers\n",n); for(i=1;i<=n;i++) scanf("%d",&s[i]); printf("enter d\n");scanf("%d",&d);flag=sos(n,s,d);if (flag==0) printf("no solution\n");getch();

This problem is an example for the Backtracking technique. A set S s1 , s2 ,L, of

integers and another integer d are given, and a subset of set S is to be found such that the elements of this subset add up to exactly d . Using backtracking technique, this solved as follows. The element is is considered with the subset { 1s ,L, to see whether their

sum total exceeds, or is exactly equal to, or is below integer d . If the total exceeds d , then is is not included into the subset. If the total is exactly d , then is is included into the

subset, a solution is found and it is reported. If the total falls below d , then is is included into the subset but a solution has not been found yet. This generates a state space tree

in which considering each is creates two states, one with is and one without is . The state space tree will have height n , because there are n elements in set S . By searching

the leaf level of this tree for d , and by working upwards to the root of this tree to find out which elements of S were added so as to get

d , the solution to this problem is obtained.The code for this technique can be written recursively because, at each step the program

has to decide whether to include is or not. The code here solves this program iteratively.The function sos receives n, array s representing the set S , and integer d from the main

function. In the function sos, the 1D array sst represents the state space tree to be generated. The root of this tree (i.e., sst[1]) contains 0, since no elements of S have been considered yet. This root has 2 children, the left child having the total with considering 1s and the right child having the total without considering 1s . From the point of view of the root whose sst array index is k=1, the left child is obtained by 2k (i.e., sst[2]) and the right child by 2k+1 (i.e., sst[3]). From the point of view of the child (whether right or left), its parent (the root) is obtained by dividing its sst index number k/2. This idea of parent-child relationship is very similar to that of a heap, and that is why the index of the root element is starting from 1 and not from 0.

In the ith level of the tree, the ith element of S is considered. The number of subtotals tobe computed (i.e., the number of nodes) at that level is 2i . To compute 2i and other powers, afunction power has been written and the variable j walks from left to right in that level to compute the subtotals. A flag variable has been used as a flip-flop because, if one time the subtotal is calculated with is , the next time it is calculated without is .element is accessed from 1 to 1, i.e., 20 to 21 −1 . At level 1, the tree elements are accessed from2 to 3, i.e., 12 22 − 1 . At level 2, the tree elements are accessed from 4 to 7, 22 to 23 − Similarly, at the last (nth) level, the tree elements are accessed from 2n to 2n − 1 . An index j

used to walk through this list. If there is a solution to the problem, then the integer d will be available at some position j (i.e., sst[j]) at this level. Now, after finding d in this level, if j is even, then it means that sst[j] is a left child (left child is 2k and a multiple of 2, hence even),

BNMIT ISE DEPT.

Page 33: 5th Sem ADA Manual

5 th semester ADA lab 33

i.e., the value of sst[j] was calculated by including the nth item, therefore this item must be printed. If j is odd, then it means that sst[j] is a right child (right child is 2k+1, hence odd), i.e., the value of sst[j] was calculated without including the nth item.

The task is to get all elements which when added together give d . If sst[j] was included during adding so as to get d , then its parent is checked to see whether it was also included in adding so as to get d . This is done by checking whether the parent is an odd child or an even child of its parent (i.e., sst[j]’s grandparent). In this way, by checking all the way up to the root of the state space tree, a subset of S whose elements add to d is obtained. There might be other occurrences of d on the nth level, all of which give valid solutions to this problem.

zeroth level, there are 20 nodes. In the first level, there are 12 nodes. In the nth level,

2n nodes. On adding all this, we have 20 21 22 L 2n O(2n )

BNMIT ISE DEPT.

Page 34: 5th Sem ADA Manual

5 th semester ADA lab 34

PROGRAM 12a: Implement Horspool algorithm for String Matching.

#include <stdio.h>#include <conio.h>#include <string.h>

void shifttable(char p[], int m, int table[]){ int j;

for(j=0;j<=255;j++) table[j] = m;for(j=0;j<=m-2;j++) table[p[j]] = m-1-j;

}

int horspool(char t[], int n, char p[], int m){ int i, k, table[300];

shifttable(p,m,table); i=m-1;while (i <= n-1){ k=0;

while ((k <= m-1) && (p[m-1-k] == t[i-k])) k++;if (k==m) return i-m+1;else i=i+table[t[i]];

}

}return -1;

void main(){ char t[100], p[15],temp;

int m,n,ret=-1,i; clrscr();printf("enter the main string in which to search\n");gets(t);n=strlen(t);printf("enter the pattern string\n");gets(p);m=strlen(p);ret=horspool(t,n,p,m);if (ret == -1) printf("search failed\n");else printf("pattern found at position %d\n",ret);getch();

}

This problem uses a technique called Input enhancement, where the input is preprocessed so that queries run faster. The search pattern of length m is processed and a table called shift-table is created by the shifttable function. This table has an integer shift value for all characters in the alphabet. For characters which are not in the pattern, their entries just contain the length of the pattern. For characters which are in the pattern, their entries contain the distance from the character’s rightmost occurrence to the rightmost character in the pattern. No shift-table entry will have 0 or negative values.

In the function horspool, the pattern is aligned to the beginning of the text which has length n. The string matching starts by comparing the last character of the pattern p[m-1] with the character of the text t[i] against which it is aligned. If these two characters are same, then the previous characters in both the pattern and the text are compared (i.e., p[m-2] and t[i-1]). This goes on either till the full pattern exactly matches the text’s characters, or until an unmatching character pair is found. When this happens, the first compared character t[i] in the

BNMIT ISE DEPT.

Page 35: 5th Sem ADA Manual

5 th semester ADA lab 35

text is looked up in the shift-table and the pattern jumps by the amount specified there. This continues as long as the text is not finished.

There are two while loops in the function horspool. The outer one has i running from m-1 to n-1, i.e., at most n-m-1 times. The inner one has k running from 0 to m-1, i.e., at most mtimes. On multiplying these two terms, we get O(nm) .

BNMIT ISE DEPT.

Page 36: 5th Sem ADA Manual

5 th semester ADA lab 36

PROGRAM 12b: Find the Binomial Co-efficients using Dynamic Programming.

#include <stdio.h>#include <conio.h>

void bincoeff(int a[][50],int n){ int i,j;

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

a[i][i]=1;

}

}for(i=2;i<=n;i++)

for(j=1;j<=i-1;j++)a[i][j] = a[i-1][j] + a[i-1][j-1];

void main(){ int n,a[50][50],i,j;

clrscr();printf("enter n, where coefficients of (a+b)^n are required\n");scanf("%d",&n);bincoeff(a,n);printf("the coefficients of (a+b)

^%d are ",n);for(i=0;i<=n;i++) printf("%d ",a[n][i]);getch();

}

This problem is an example for dynamic programming technique. Binomial coefficientsare the numerical coefficients of the expansion of (a b)n . For eg., for power 2, the numerical

coefficients are 1, 2 and 1, because on expanding (a b)2 , we a 2 2ab b2 . This is the same as computing a row (3rd row) of the Pascal triangle.

Dynamic programming is used here because of the following property in Pascal’s triangle, which is stored in the 2D array a: any entry a[i][j] can be computed by adding a[i-1][j] and a[i-1][j-1]. This computation stops when the base cases occur, and this happenswhen either or both indices become 0. This is because the numerical coefficients of both a and

bn in the expansion of (a b)n , for any n , are 1.The running-time of this code is the time that is taken to generate Pascal’s

Expansion of (a has 1 coefficient, i.e. 1. Expansion of (a b has 2 coefficients, i.e., 1

and 1. Expansion of (a has 3 coefficients. Similarly, expansion of (a has n coefficients. All of these have to be generated using bottom-up dynamic programming, so

adding 1 2 3 L (n )1 , (n )1 (n 2)

, which works out to O(n2

) .

BNMIT ISE DEPT.

Page 37: 5th Sem ADA Manual

5 th semester ADA lab 37

PROGRAM 13: Find the Minimum Cost Spanning Tree of a given undirected graph usingPrim’s algorithm.

#include <stdio.h>#include <conio.h>

void prim(int cost[][10], int n, int mst[][10]){ int visited[10]={0}, min_edge_weight=999,u,v,i,j,vertices=0;

visited[1]=1;vertices++;while (vertices < n){ for(i=1;i<=n;i++)

for(j=1;j<=n;j++){ if ((visited[i] == 1) && (visited[j] != 1) &&

(cost[i][j] < min_edge_weight)){ min_edge_weight = cost[i][j];

u=i,v=j;

}}

}}

visited[v]=1;vertices++; mst[u][v]=mst[v][u]=min_edge_weight; min_edge_weight=999;

void main(){ int i,j,n,cost[10][10],mst[10][10]={0},total=0;

clrscr();printf("enter number of vertices in the undirected graph\n");scanf("%d",&n);printf("enter the cost matrix of the graph, with 999 for no edges\n");for(i=1;i<=n;i++)

for(j=1;j<=n;j++)scanf("%d",&cost[i][j]);

prim(cost,n,mst);printf("a MST for the given graph is\n");for(i=1;i<=n;i++)

for(j=1;j<=n;j++)if ((j>i) && (mst[i][j] != 0)){ printf("%d - %d\n",i,j);

total=total+mst[i][j];}

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

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

}

}printf("the total cost of this MST is %d\n",total);getch();

This problem is an example for the Greedy technique. The program starts with some vertex and finds out the smallest edge coming out of that vertex so that, one vertex of that edge is already visited and the other vertex of that edge is not visited. In some ith iteration of the Prim’s algorithm, the graph is divided into 2 parts, where one part is the component in which all vertices are visited, and another part is the component in which all vertices are unvisited. In this scenario,

Page 38: 5th Sem ADA Manual

5 th semester ADA lab 38

an edge is to be picked up so that its weight is minimum among all unpicked edges, and this edge goes from a vertex in the visited component to another vertex in the unvisited component.

Once this edge is added to the MST, the unvisited vertex is made visited and therefore, it joins the visited component. A 2D array called mst stores the weight of the edge u-v in mst[u][v], so that this information is available to the main function. The function stops when all the vertices have been visited.

To find the minimum edge each time, the function prim looks at the upper half of the matrix cost (as the input graph is undirected, the upper and lower halves of cost matrix identical). This takes time roughtly n2 / 2 . This is done once for each vertex, and there are nvertices, so the overall running-time of this implementation is O(n3 ) .

BNMIT ISE DEPT.

Page 39: 5th Sem ADA Manual

5 th semester ADA lab 39

PROGRAM 14b: Compute the transitive closure of a given directed graph using Warshall’s algorithm.

#include <stdio.h>#include <conio.h>

void warshal(int adjm[][10], int n){ int i,j,k;

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

for(j=1;j<=n;j++)adjm[i][j] = adjm[i][j] || (adjm[i][k] &&

adjm[k][j]);}

void main(){ int n, i,j,adjm[10][10];

clrscr();printf("enter the number of vertices in the given digraph\n");scanf("%d",&n);printf("enter the adjacency matrix of graph\n");for(i=1;i<=n;i++)

for(j=1;j<=n;j++)scanf("%d", &adjm[i][j]);

warshal(adjm,n);printf("the transitive closure of entered digraph\n");for(i=1;i<=n;i++){ for(j=1;j<=n;j++)

printf("%d ",adjm[i][j]);printf("\n");

}

}getch();

This program is an example for Dynamic programming, and the code is similar to that of Floyd’s algorithm (Program 5b), but the functionality of these two programs are very different. Warshall’s algorithm computes the transitive closure of a graph. In the transitive closure of a given graph, there is a 1 between vertices u and v if there is a path (direct edge or a multi-edged path) between u and v.

If there is an edge/path between u and some intermediate vertex t, and, if there is an edge/path between t and v, then there is a path between u and v. To find this, all vertices other than u and v need to be put in the place of t and checked. This is done for all combinations of u and v. The matrix adjm itself is modified, if need be, each time a new vertex is considered for t. There are C2

with all other n − 2 vertices as intermediate vertices. This works out to O(n3 ) .

BNMIT ISE DEPT.

Page 40: 5th Sem ADA Manual

5 th semester ADA lab 40

PROGRAM 15: Implement n-queens problem using Back tracking.

#include <stdio.h>#include <conio.h>

int x[20]={0};

int abs(int y){ int i=0;

if (y>=0) return y;else{ while(y<=0) { y++, i++; }

return --i;

}}

int place(int k, int i){ int j;

for(j=1;j<=k-1;j++)if ((x[j] == i) || (abs(x[j]-i) == abs(j-k))) return 0;

return 1;}

void nqueens(int k, int n){ int i,j;

for(i=1;i<=n;i++){ if (place(k,i))

{ x[k]=i;if (k==n){ for(j=1;j<=n;j++) printf("%d ",x[j]);

printf("\n");

}}

}

}else nqueens(k+1,n);

void main(){ int n;

clrscr();printf("enter the number of queens to place\n");scanf("%d",&n); nqueens(1,n); getch();

}

An n chessboard and n queens are given. All n queens are to be placed on the givenchessboard so that no queen cancels out any other queen. Queens cancel other pawns (including other queens) horizontally, vertically and diagonally. This problem can be solved using the Backtracking technique.

The array x is made global and this is the solution vector, i.e., if the 3rd queen is placed in column 2 of the third row, then x[3]=2. It should also be noted that a kth queen is always placed in the kth row and the program has to decide upon which column among the n columns of the kth

row to place it in.The function place takes in two values, k and i, and returns 1 if kth queen can be placed

in column i, otherwise returns 0. It checks this by seeing whether i is the same as a column in

BNMIT ISE DEPT.

Page 41: 5th Sem ADA Manual

5 th semester ADA lab 41

which an earlier queen was placed, because if so, then the kth queen cannot be placed in that column (check for vertical cancellation). It also checks whether the cell at the kth row and the ith column is in the same diagonal as any previously placed queen, because if so, then the kth

queen cannot be placed at that particular cell (check for diagonal cancellation). There is no need to check for horizontal cancellation, because no 2 queens are kept in the same row.

The function nqueens gets either 1 or 0 from place function and if the return value is 1, the kth queen is placed in the ith column. If not, then a queen cannot be placed in that column, so the next (i.e., k+1th) queen is considered. If k=n, then the nth queen was successfully placed into a column, which means we have a solution to the n -queens problem, so the solution vector is reported.

This code generates an implicit state space tree. For the 4-queens problem, the number of nodes of the state space tree is as follows. At the zeroth level, there is only one, i.e., 40 , node. At the first level, there are 4, i.e., 14 , nodes, and in the next level, each of these 4 nodes will have 4 nodes each (of course, many of these nodes do not represent solutions), so at the second there are 16, i.e., 42 , nodes. At the 4th level (which is the n th level for 4-queens problem), thereare nodes.

Similarly, for the n -queens problem, the number of nodes at the zeroth level is n0 . At thefirst level, it is 1n . At the second level, it is n2 . So at the n th level, it is nn . On adding all thesenumber of nodes at each level, we get n0 n1 n2 L nn , which works out

n − 1 , which

O(nn ) .n −

BNMIT ISE DEPT.