Program
#include #include #define N 3 #define EPSILON 1e-10 typedef enum {FALSE, TRUE} bool; void print( double a[][N] ) { /* * print the matrix. */ int i, j; for( i=0; i EPSILON ) { printf( "factor=%g dividing row %d by %g... ", factor, i, temp ); divRow( a, i, temp ); print(a); factor *= temp; } temp = a[j][j]; if( fabs(temp) > EPSILON && fabs(temp-1.0) > EPSILON ) { printf( "factor=%g dividing row %d by %g... ", factor, j, temp ); divRow( a, j, temp ); print(a); factor *= temp; } if( fabs(a[i][j]) > EPSILON ) { printf( "factor=%g row[%d] -= row[%d]... ", factor, i, j ); subRow( a, i, j ); print(a); } if( anyZero(a) == TRUE ) return 0; } a[N-1][N-1] *= factor; // all but(?) last element of row N-1 are zero. return 1; } double multDia( double a[][N] ) { /* * returns multiplication of diagonal elements. */ int i; double factor = 1; for( i=0; i
Explanation
factor = 1. for i=1 to N-1 do for j=0 to i-1 do divide row i by D[i][j] // divRow(). factor *= D[i][j]. divide row j by D[j][j] // divRow(). factor *= D[j][j]. subtract elements of row j from corresponding elements of row i // subRow(). check for any of the diagonal elements of D to be 0. // anyZero(). determinant = factor*product of diagonal elements.
| 8 0 1 | | 2 1 3 | | 5 3 9 |. factor = 1.
Snapshots of the algorithm when run on this determinant are shown here.
I |
J |
STEP |
FACTOR |
DETERMINANT |
---|---|---|---|---|
1 |
0 |
divide row 1 by |
2 |
|8 0 1 | |
|1 0.5 1.5 | |
||||
|5 3 9 | |
||||
1 |
0 |
divide row 0 by 8 |
16 |
| 1 0 0.125 | |
| 1 0.5 1.5 | |
||||
| 5 3 9 | |
||||
1 |
0 |
row 1 −= row 0| |
16 |
| 1 0 0.125 | |
| 0 0.5 1.375 | |
||||
| 5 3 9 | |
||||
2 |
0 |
divide row 2 by 5 |
80 |
| 1 0 0.125 | |
| 0 0.5 1.375 | |
||||
| 1 0.6 1.8 | |
||||
2 |
0 |
row 2 −= row 0 |
80 |
| 1 0 0.125 | |
| 0 0.5 1.375 | |
||||
| 0 0.6 1.675 | |
||||
2 |
1 |
divide row 2 by 0.6 |
48 |
| 1 0 0.125 | |
| 0 0.5 1.375 | |
||||
| 0 1 2.792 | |
||||
2 |
1 |
divide row 1 by 0.5 |
24 |
| 1 0 0.125 | |
| 0 1 2.75 | |
||||
| 0 1 2.792 | |
||||
2 |
1 |
row 2 −= row 1 |
24 |
| 1 0 0.125 | |
| 0 1 2.75 | |
||||
| 0 0 0.0417| |
||||
Thus, the determinant = 24*(1*1*0.0417) = 1. |
Points to Remember
Program
#include #define M 3 #define N 3 int findMin( int a[][N], int row ) { /* * find min value in row of a. * return the value. */ int min = a[row][0]; int j; for( j=1; j max ) max = a[i][col]; return max; } void saddle( int a[][N] ) { /* * finds ALL saddle points of a if exist. */ int i, j; for( i=0; i
Explanation
| 1 2 3 | a = | 4 5 6 | | 7 8 9 |
for i=0 to M-1 { min = minimum value in row i. // findMin(). for j=0 to N-1 { max = maximum value in column j. // findMax(). if (min == max) print "saddle found at row ", i, "and column ", j. } }
Points to Remember
Write a function mmult() to multiply two sparse matrices and store the result in another sparse matrix. Each sparse matrix is represented by an array of triplets. Each triplet consists of a row, a column, and a value.
Program
#include #define M 10 // the matrices are MxP, PxN and MxN. #define P 7 #define N 8 void ftrans( int a[][3], int b[][3] ) { /* * finds fast-transpose of a in b. */ int t[P+1]; int i, j, n, terms; int temp, temp2; n = a[0][1]; terms = a[0][2]; b[0][0] = n; b[0][1] = a[0][0]; b[0][2] = terms; if( terms <= 0 ) return; for( i=0; i
Explanation
I |
A[I][0] |
A[I][1] |
A[I][2] |
||
---|---|---|---|---|---|
0 |
7 |
7 |
8 |
||
1 |
1 |
1 |
15 |
||
2 |
1 |
4 |
22 |
||
3 |
1 |
6 |
−15 |
||
4 |
2 |
2 |
11 |
||
5 |
2 |
3 |
3 |
||
6 |
3 |
4 |
−6 |
||
7 |
5 |
1 |
91 |
||
8 |
6 |
3 |
28 |
||
a[0][0]=7 is the number of rows of the matrix a. a[0][1]=7 is the number of columns of the matrix a. a[0][2]=8 is the number of nonzero elements in the matrix a. The nonzero elements are saved in rows i=1 to i=8 where a[i][0] is the row, a[i][1] is the column, and a[i][2] is the value in the matrix a. Note that the elements are sorted by row, but inside a row they are sorted by columns.
I |
T[I] |
||
---|---|---|---|
0 |
0 |
||
1 |
1 |
||
2 |
4 |
||
3 |
6 |
||
4 |
0 |
||
5 |
7 |
||
6 |
8 |
||
t[i] == 0 signifies that row i of b does not contain any elements. Because of this, the original binary search of order O(log n) can now be done in O(1) time. But this needs extra O(Nb) time to construct t[] where Nb is the number of non-zero entries in b.
| 0 2 | a = | 3 0 |, b = | 0 0 5 | | 0 0 | | 7 0 6 | | 1 4 |
Here M = 4, P = 2, and N = 3. Then we should get
| 14 0 12 | c = | 0 0 15 | | 0 0 0 | | 28 0 29 |
The algorithm traverses each element of a, and for each element in a with row arow and column acol:
row acol of b is traversed
the element in a is multiplied by each element in the row-list of b with row acol and column bcol, and
the products are inserted in c as c[arow][bcol].
Thus in every step, an element in a contributes to c. If c[arow][bcol] exists, the product is added to the original value. The multiplication of a and b is given here for the previous example.
STEP |
AROW |
ACOL |
BCOL |
A[AROW][ACOL] *B[ACOL][BCOL] |
C[AROW][BCOL] |
---|---|---|---|---|---|
1 |
0 |
1 |
0 |
14 |
14 |
2 |
0 |
1 |
2 |
12 |
12 |
3 |
1 |
0 |
2 |
15 |
15 |
4 |
3 |
0 |
2 |
5 |
5 |
5 |
3 |
1 |
0 |
28 |
28 |
6 |
3 |
1 |
2 |
24 |
29 |
Note that in step 6, the product is 24, while c[3][2] gets a value of 29. This happens because c[3][2] already contains a value 5 in step 4.
Points to Remember
Let a and b be two sparse matrices. Write a function sMatMul(a, b, c) to set up the structure for c=a*b.
Program
#include #define M 10 #define N 10 #define P 10 #define DEFAULTVAL 0 #define SUCCESS 0 #define ERROR -1 typedef int type; typedef struct node node; struct node { type data; int row; int col; node *hnext; node *vnext; }; typedef struct { node *rows; node *cols; } spmat; void sInit( spmat *mat, int rows, int cols ) { /* * initialize the matrix. */ int i; mat->rows = (node *)malloc( sizeof(node)*rows ); mat->cols = (node *)malloc( sizeof(node)*cols ); for( i=0; irows[i].hnext = mat->rows+i; mat->rows[i].row = i; } for( i=0; icols[i].vnext = mat->cols+i; mat->cols[i].col = i; } } int sAdd( spmat *mat, int row, int col, type data ) { /* * adds a new node to the sparse matrix. */ node *ptr; if( data == DEFAULTVAL ) return; ptr = (node *)malloc( sizeof(node) ); // freed in cColInsert() if reqd. ptr->data = data; ptr->row = row; ptr->col = col; cRowInsert( mat->rows+row, ptr ); cColInsert( mat->cols+col, ptr ); return SUCCESS; } int cRowInsert( node *head, node *dataptr ) { /* * inserts dataptr in appropriate row of sparse matrix. */ node *ptr, *prev; for( prev=head, ptr=prev->hnext; ptr!=head && ptr->colcol; prev=ptr, ptr=ptr->hnext ) ; if( ptr!=head && ptr->col == dataptr->col ) { // data already exists. ptr->data += dataptr->data; // this is for multiplication. return SUCCESS; } // dataptr should be added between prev and ptr. dataptr->hnext = ptr; prev->hnext = dataptr; return SUCCESS; } int cColInsert( node *head, node *dataptr ) { /* * inserts dataptr in appropriate col of sparse matrix. * Assume that cRowInsert() was called before. */ node *ptr, *prev; for( prev=head, ptr=prev->vnext; ptr!=head && ptr->rowrow; prev=ptr, ptr=ptr->vnext ) ; if( ptr!=head && ptr->row == dataptr->row ) { // data already exists. free(dataptr); return SUCCESS; } // dataptr should be added between prev and ptr. dataptr->vnext = ptr; prev->vnext = dataptr; return SUCCESS; } void cRowPrint( node *head ) { /* * print a row. */ node *ptr; printf( "%2d : ", head->row ); for( ptr=head->hnext; ptr!=head; ptr=ptr->hnext ) printf( "%d(%d,%d) ", ptr->data, ptr->row, ptr->col ); printf( " " ); } void cColPrint( node *head ) { /* * print a col. */ node *ptr; printf( "%2d : ", head->col ); for( ptr=head->vnext; ptr!=head; ptr=ptr->vnext ) printf( "%2d(%d,%d) ", ptr->data, ptr->row, ptr->col ); printf( " " ); } void sHPrint( spmat *mat, int rows ) { /* * print sparse matrix by traversing it row-wise. */ int i; for( i=0; irows+i ); printf( " " ); } void sVPrint( spmat *mat, int cols ) { /* * print sparse matrix by traversing it col-wise. */ int i; for( i=0; icols+i ); printf( " " ); } type sGetVal( spmat *a, int row, int col ) { /* * return a[row][col]; */ node *head = a->rows+row; node *ptr; for( ptr=head->hnext; ptr!=head; ptr=ptr->hnext ) if( ptr->col == col ) return ptr->data; return DEFAULTVAL; // entry absent in matrix : default value 0. } int sMatMulBad( spmat *a, spmat *b, spmat *c ) { /* * original inefficient implementation of matrix mult. */ int i, j, k; for( i=0; irows[i].hnext; ptri!=a->rows+i; ptri=ptri->hnext ) int row = ptri->col; for( ptrj=b->rows[row].hnext; ptrj!=b->rows+row; ptrj=ptrj->hnext ) { sAdd( c, i, ptrj->col, ptri->data*ptrj->data ); } } return SUCCESS; } int main() { spmat a, b, c; sInit(&a,M,P); sInit(&b,P,N); sInit(&c,M,N); sAdd( &a, 0,1, 2 ); sAdd( &a, 1,0, 3 ); sAdd( &a, 3,1, 4 ); sAdd( &b, 0,2, 5 ); sAdd( &b, 1,0, 7 ); sAdd( &b, 1,1, 6 ); sHPrint(&a,M); sHPrint(&b,P); sMatMul( &a, &b, &c ); sHPrint(&c,M); sVPrint(&c,N); return 0; }
Explanation
| 0 2 | a = | 3 0 |, b = | 0 0 5 | | 0 0 | | 7 0 6 | | 1 4 |
Here M = 4, P = 2, and N = 3. Then we should get
| 14 0 12 | c = | 0 0 15 |. | 0 0 0 | | 28 0 29 |
STEP |
AROW |
ACOL |
BCOL |
A[AROW][ACOL]*B [ACOL][BCOL] |
C[AROW][BCOL] |
---|---|---|---|---|---|
1 |
0 |
1 |
0 |
14 |
14 |
2 |
0 |
1 |
2 |
12 |
12 |
3 |
1 |
0 |
2 |
15 |
15 |
4 |
2 |
||||
5 |
3 |
0 |
2 |
5 |
5 |
6 |
3 |
1 |
0 |
28 |
28 |
7 |
3 |
1 |
2 |
24 |
29 |
Step 4 signifies that a[4] is taken for traversal but is not traversed as it is empty. Note that the product is 24 in step 7, while c[3][2] gets a value of 29. This happens because c[3][2] already contains a value of 5 in step 5.
Points to Remember
Program
#include #include #define N 80 #define K 2 // K-way merge. #define DATAFILE "main.txt" #define TEMPFILE "temp.txt" typedef struct node node; typedef enum {FALSE, TRUE} bool; struct node { int val; char s[N]; }; node buf[K]; // buffer used for merging. int rec[K]; // record numbers of nodes in buffer. int getNRecords( char *filename ) { /* * returns no of records in file filename using size of the file. */ int off; FILE *fp = fopen( filename, "r" ); fseek (fp, 0, SEEK_END ); off = ftell(fp)/sizeof(node); // no of records. fclose(fp); return off; } void writeToFile( char *filename, node *n ) { /* * writes record n to file filename. */ FILE *fp = fopen( filename, "a" ); fwrite( n, sizeof(node), 1, fp ); fclose(fp); } void readFromFile( char *filename, node *n, int off ) { /* * reads a record at offset off from file filename into n. * off is number of records before the record in the file (NOT bytes). * off starts from 0. */ FILE *fp; //printf( "reading rec no %d... ", off ); if( off >= getNRecords(filename) ) { fprintf( stderr, "ERROR: reading beyond the file. " ); return; } printf("total records are %d ",getNRecords(filename)); fp = fopen( filename, "r" ); fseek( fp, off*sizeof(node), SEEK_CUR ); fread( n, sizeof(node), 1, fp ); fclose(fp); } void writeFun( char *filename ) { /* * writes some data to filename. */ node data[10] = { {5,"five"}, {3,"three"}, {4,"four"}, {8,"eight"}, {7,"seven"}, {6,"six"}, {9,"nine"}, {10,"ten"}, {1,"one"}, {2,"two"} }; int i; for( i=0; i<10; ++i ) writeToFile( filename, data+i ); } void readFun( char *filename ) { /* * reads filename and prints the data. */ node n; int i, nrec = getNRecords(filename); for( i=0; i= nrec ) break; rec[i] = startoff; printf( "buf[%d]=%d. ", i, startoff ); readFromFile( srcfile, buf+i, startoff ); } for( ; i−1; getchar(); } void updatebuf( node *buf, int *rec, int *rec2, int prevrec, int l, char *srcfile, int nrec ) { /* * updates buf+rec2 as rec2[prevrec] was output. * read appropriate record from srcfile if necessary. * rec still contains the original rec nos which can be used for * checking ends of runs. * l is runlength. */ if( rec2[prevrec] < nrec-1 && rec2[prevrec] < rec[prevrec]+l−1 ) { // rec2[prevrec] was NOT the last rec of that run. rec2[prevrec]++; readFromFile( srcfile, buf+prevrec, rec2[prevrec] ); } else { // rec2[prevrec] was the last rec of that run. rec2[prevrec] = −1; // job of this run is over. } } int getMin( node *buf, int *rec2 ) { /* * returns index in buf of that record which has min sorting value. * rec2 is needed for checking whether a buf entry is valid. */ int minval = 9999; int minindex = −1; int i; for( i=0; i−1 && buf[i].val < minval ) { minval = buf[i].val; minindex = i; } return minindex; } void merge( char *srcfile, char *dstfile, node *buf, int *rec2, int l, int nrec ) { /* * rec2 contains record numbers being compared; global rec also contains * the same at this point. * buf contains their actual data. * l is runlength. * srcfile is needed for reading next data. * the data is appended to dstfile. * total no of records being written is min(l*k,nrec-rec[0]). */ int totalrec = l*K; int i; int nrecremaining = nrec-rec[0]; // no of rec in srcfile yet to be written to dstfile. if( nrecremaining < totalrec ) totalrec = nrecremaining; printf( "totalrec=%d nrecremaining=%d. ", totalrec, nrecremaining ); for( i=0; i−1 ) { fprintf( stderr, "ERROR: merge(): all rec2 are −1! " ); return; } //printf( "min=%d. ", nextrec ); // this is the index in rec2 of next record to be output. writeToFile( dstfile, buf+nextrec ); // remove this written record. read new record from srcfile if needed. updatebuf( buf, rec, rec2, nextrec, l, srcfile, nrec ); //printf( "after updatebuf : rec2=%d %d %d. ", rec2[0], rec2[1], rec2[2] ); } } void mergedriver( char *srcfile, char *dstfile ) { /* * sort+merge srcfile and store in dstfile. */ int nrec = getNRecords(srcfile); int i, l; int rec2[K]; char tempname[N]; for( l=1; l
Explanation
STEP |
FILE |
RUNLENGTH |
||
---|---|---|---|---|
1 |
5 3 4 8 7 6 9 10 2 1 |
1 |
||
2 |
3 4 5 6 7 8 2 9 10 1 |
3 |
||
3 |
2 3 4 5 6 7 8 9 10 1 |
9 |
||
4 |
1 2 3 4 5 6 7 8 9 10 |
27 |
||
Points to Remember
Find a rectangular region in a matrix with the maximum sum of its elements. The elements may be negative.
Program
#include #define COLS 5 #define MININT -99999 int filter(int a[][COLS], int i, int j, int k, int l, int rows, int cols) { /* * filter the matrix of size k*l starting from a[i][j]. * size of the matrix is rows*cols. * k, l start with 1. */ int iii, jjj; int sum = 0; if(i+k > rows || j+l > cols) // the matrix was already considered // with smaller k, l. return MININT; for(iii=0; iii maxsum) { maxsum=sum, maxrow1=i, maxcol1=j, maxrow2=i+k−1, maxcol2=j+l−1; } } printf("sum=%d. ", filter(a, maxrow1, maxcol1, maxrow2-maxrow1+1, maxcol2-maxcol1+1, rows, cols)); printMatrix(a, maxrow1, maxcol1, maxrow2-maxrow1+1, maxcol2-maxcol1+1, rows, cols); } int main() { int a[][COLS] = { {5,−1,−2,−4,1}, {−3,2,10,−6,3}, {−1,9,−11,−7,9}, {3,101,3,−2,−96}, {−1,−2,0,3,−3}, {−1,−2,−3,2,−3} }; plateau(a, sizeof(a)/COLS/sizeof(int), COLS); return 0; }
Explanation
| 5 −1 −2 −4 1 | | 5 −1 | | −3 2 10 −6 3 | | −3 2 | | −1 9 −11−7 9 | | −1 9 | sum = 115. | 3 101 3 −2 −96 | | 3 101| | −1 −2 0 3 −3 | | −1 −2 −3 2 −3 |
An example matrix and its maximum-sum-plateau.
for i=0 to rows-1 for j=0 to columns-1 { maxsum = matrix[i][j]. for height=1 to rows for width=1 to columns { let M = matrix of size height x width from matrix[i][j]. let sum = sum of elements of M. if sum > maxsum maxsum = sum. } }
The values of i, j, width, and height at any point represent the matrix. Those values can be saved to print the matrix at the end of the algorithm.
The complexity of this procedure is O(m*m*m*n*n*n) where the size of the original matrix is m × n. The complexity of finding the sum of elements of M is O(m*n).
Let i=1 and j=2. matrix[i][j] = 10. Let height = 2 and width = 1. Thus the matrix contains two elements in it, {10, −11} and the sum is −1. Since the sum is negative, there is no point in increasing the size of the matrix and considering other elements because whatever their sum (say s), by adding this matrix to it, the total sum is definitely going to be lower than s. The matrix containing sum s may be a candidate for the result. So our matrix cannot have a sum greater than the final result. Thus, if we increase the height of the matrix further so that the elements are {10, −11, 3}, the sum becomes 2 which is less than a 1 × 1 matrix starting from 3. Instead, if we increase the width so that the elements are {10, −11, −6, −7}, the sum is −14 which is even lower.
The function filter() implements this strategy.
Points to Remember
Write a program that takes strings as inputs and stores them in a hash table. It should then ask the user for strings to be searched in the hash table. Use shift- folding as the hashing function and chaining for overflow handling.
Program
#include #include #include #define MAXLEN 80 #define HASHSIZE 23 // some prime val. #define SHIFTBY 3 // each group size in hashing. typedef struct node node; typedef char *type; typedef node *hashtable[HASHSIZE]; struct node { int val; char *key; node *next; }; int hGetIndex(char *key) { /* * returns index into hashtable applying hash function. * uses shift-folding followed by mod function for hashing. */ int i, n, finaln=0; char *keyptr; for(keyptr=key; *keyptr; finaln+=n) for(i=0, n=0; ikey = strdup(key); ptr->val = val; ptr->next = h[index]; h[index] = ptr; printf("h[%d] = %s. ", index, key); } int hGetVal(hashtable h, char *key) { /* * returns val corresponding to key if present in h else −1. */ node *ptr; for(ptr=h[hGetIndex(key)]; ptr && strcmp(ptr->key, key); ptr=ptr->next) ; if(ptr) return ptr->val; return −1; } void printHash(hashtable h) { /* * print the hashtable rowwise. */ int i; node *ptr; for(i=0; inext) printf("%s=%d ", ptr->key, ptr->val); printf(" "); } } int main() { char s[MAXLEN]; int i = 0; hashtable h = {"abc"}; printf("Enter the string to be hashed: "); gets(s); while(*s) { hInsert(h, s, i++); printf("Enter the string to be hashed(enter to end): "); gets(s); } printf("Enter the string to be searched: "); gets(s); while(*s) { printf("%s was inserted at number %d. ", s, hGetVal(h, s)); printf(" Enter the string to be searched(enter to end): "); gets(s); } //printHash(h); return 0; }
Explanation
Points to Remember
Write functions to insert and search in a hash table by using the rehashing technique. Use linear probing if the rehashing fails.
Program
#include #include #include #define MAXLEN 80 #define HASHSIZE 23 // some prime val. typedef struct node node; typedef char *type; typedef node *hashtable[HASHSIZE]; struct node { int val; type key; }; int hGetIndex1(type key) { /* * returns index into hashtable applying hash function. * uses sum of elements followed by mod function for hashing. */ int n=0; char *keyptr; for(keyptr=key; *keyptr; ++keyptr) n += *keyptr; return n%HASHSIZE; } int hGetIndex2(type key) { /* * returns index into hashtable applying hash function. * sums the products of elements with their indices and then mod. */ long n=0; int i; type keyptr; printf("Function 2:). "); for(keyptr=key, i=1; *keyptr; ++keyptr, ++i) n += i**keyptr; return n%HASHSIZE; } int hGetEmptySlot(hashtable h, int index) { /* * search for an empty slot in h starting from index+1. */ int i; for(i=index+1; i−1; } int hLinearProbe(hashtable h, type key, int index) { /* * search for node having key in h starting from index+1. */ int i; for(i=index+1; ikey, key)) return i; else if(!h[i]) return −1; for(i=0; ikey, key)) return i; else if(!h[i]) return −1; return −1; } void hInsert(hashtable h, type key, int val) { /* * insert s in hashtable h. * does NOT check for duplicate insertion. */ node *ptr = (node *)malloc(sizeof(node)); int index = hGetIndex1(key); if(h[index]) { index = hGetIndex2(key); if(h[index]) { index = hGetEmptySlot(h, index); if(index == −1) { printf("ERROR: Hashtable full. "); return; } } } ptr->key = strdup(key); ptr->val = val; h[index] = ptr; printf("h[%d] = %s. ", index, key); } int hGetVal(hashtable h, type key) { /* * returns val corresponding to key if present in h else −1. */ int index = hGetIndex1(key); if(h[index] && strcmp(h[index]->key, key)) { index = hGetIndex2(key); if(h[index] && strcmp(h[index]->key, key)) { index = hLinearProbe(h, key, index); if(index == −1) return −1; } else if(!h[index]) return −1; } else if(!h[index]) return −1; printf("index=%d ", index); return h[index]->val; } void printHash(hashtable h) { /* * print the hashtable. */ int i; for(i=0; ikey, h[i]->val); printf(" "); } } int main() { char s[MAXLEN]; int i = 0; hashtable h = {"asd"}; printf("Enter the string to be hashed: "); gets(s); while(*s) { hInsert(h, s, i++); printf("Enter the string to be hashed(enter to end): "); gets(s); } printf("Enter the string to be searched: "); gets(s); while(*s) { printf("%s was inserted at number %d. ", s, hGetVal(h, s)); printf(" Enter the string to be searched(enter to end): "); gets(s); } printHash(h); return 0; }
Explanation
Points to Remember
Part I - C Language
Part II - Data Structures
Part III - Advanced Problems in Data Structures