Write functions to add, subtract, and multiply two polynomials represented as lists. Also, write a function to evaluate the polynomial for a given value of its variable.
Program
/* compile with -lm option. */ #include #include #include typedef struct node node; typedef int type; typedef node *polynomial; struct node { type coeff; type power; node *next; }; polynomial createPoly(int n, ...) { /* * create a list from the arguments. * n is the number of nodes which will be created. * thus after n there should be 2n arguments: (coeff, power) pairs. * it is assumed that their powers are decreasing. */ va_list vl; polynomial p = NULL; int i; va_start(vl, n); for(i=0; icoeff = va_arg(vl, int); ptr->power = va_arg(vl, int); ptr->next = p; p = ptr; } va_end(vl); return p; } void pPrint(polynomial p) { node *ptr; for(ptr=p; ptr; ptr=ptr->next) printf("%dx%d + ", ptr->coeff, ptr->power); printf(" "); } polynomial pSub(polynomial p1, polynomial p2) { /* * return p1-p2 recursively. */ node *ptr = (node *)malloc(sizeof(node)); if(p1 && p2 && p1->power == p2->power) { ptr->coeff = p1->coeff - p2->coeff; ptr->power = p1->power; ptr->next = pSub(p1->next, p2->next); } else if(p1 && ((p2 && p1->power < p2->power) || !p2)) { ptr->coeff = p1->coeff; ptr->power = p1->power; ptr->next = pSub(p1->next, p2); } else if(p2 && ((p1 && p1->power > p2->power) || !p1)) { ptr->coeff = -p2->coeff; ptr->power = p2->power; ptr->next = pSub(p1, p2->next); } else { // p1 == p2 == NULL. free(ptr); return NULL; } return ptr; } polynomial pAdd(polynomial p1, polynomial p2) { /* * return p1+p2 recursively. */ node *ptr = (node *)malloc(sizeof(node)); if(p1 && p2 && p1->power == p2->power) { ptr->coeff = p1->coeff + p2->coeff; ptr->power = p1->power; ptr->next = pAdd(p1->next, p2->next); } else if(p1 && ((p2 && p1->power < p2->power) || !p2)) { ptr->coeff = p1->coeff; ptr->power = p1->power; ptr->next = pAdd(p1->next, p2); } else if(p2 && ((p1 && p1->power > p2->power) || !p1)) { ptr->coeff = p2->coeff; ptr->power = p2->power; ptr->next = pAdd(p1, p2->next); } else { // p1 == p2 == NULL. free(ptr); return NULL; } return ptr; } void pInsertOrAdd(polynomial p, node *ptr) { /* * p->next anytime contains a partial product. * add ptr at appropriate place in it keeping powers in order. */ node *curr, *prev; for(prev=p, curr=prev->next; curr && curr->power < ptr->power; prev=curr, curr=curr->next) ; // prev will always be NON-NULL :). if(curr && curr->power == ptr->power) curr->coeff += ptr->coeff, free(ptr); else prev->next = ptr, ptr->next = curr; } polynomial pMult(polynomial p1, polynomial p2) { /* * return p1*p2. */ node p3, *ptr1, *ptr2, *ptr; p3.next = NULL; for(ptr1=p1; ptr1; ptr1=ptr1->next) for(ptr2=p2; ptr2; ptr2=ptr2->next) { ptr = (node *)malloc(sizeof(node)); ptr->coeff = ptr1->coeff * ptr2->coeff; ptr->power = ptr1->power + ptr2->power; pInsertOrAdd(&p3, ptr); } return p3.next; } int pEval(polynomial p1, int x) { /* * evaluate p1 at x. */ node *ptr; int result = 0; for(ptr=p1; ptr; ptr=ptr->next) result += ptr->coeff * pow(x, ptr->power); return result; } int main() { polynomial p1 = createPoly(3, 3, 5, -1, 3, -10, 0), p2 = createPoly(3, -2, 3, 0, 2, 20, 0); pPrint(p1); pPrint(p2); pPrint(pAdd(p1, p2)); pPrint(pSub(p1, p2)); pPrint(pMult(p1, p2)); printf("value of p1 at x=%d is %d. ", 2, pEval(p1, 2)); return 0; }
Explanation
(3 × 5 + 4 × 3 + 9) + (5 × 3 − 4x) = (3 × 5 + 9 × 3 − 4x + 9)
and
(3 × 5 + 4x 3 + 9) + (5 × 3 − 4x) = (3 × 5 − 1 × 3 + 4x + 9)
(3 × 5 + 4 × 3 + 9) × (5 × 3 − 4x)
= (15 × 8 − 12 × 6) + (20 × 6 − 16 × 4) + (45 × 3 − 36x)
= (15 × 8 + 8 × 6 − 16 × 4 + 45 × 3 − 36x).
Points to Remember
A linear list is maintained circularly in an array clist[0…N–1] with rear and front set up as for circular queues. Write functions to delete the k-th element in the list and to insert an element e immediately after the k-th element.
Program
#include #define N 10 // size of the list. #define FIRSTINDEX 0 // index of first element in the list. #define ILLEGALINDEX -1 // illegal index - for special cases. #define EINDEXOUTOFBOUND -1 // error code on overflow in the list. #define SUCCESS 0 // success code. typedef int type; // type of each data item. type clist[N]; // list implemented using array. int front = ILLEGALINDEX; // points to first element in the list. int rear; // points to last element in the list. int lPush( type data ) { /* * appends 'data' to the end of the list if space is available. * otherwise returns error. */ if( front == ILLEGALINDEX ) { // list empty. front = rear = FIRSTINDEX; } else if( (rear+1)%N == front ) { // list overflow. return EINDEXOUTOFBOUND; } else // normal case. rear = (rear+1)%N; // %N for wrapping around of index. clist[rear] = data; return SUCCESS; } void lPrint() { /* * prints elements in the list from front to rear. */ int i; int nelem = lGetNElements(); for( i=0; i nelem || k < 1 ) return EINDEXOUTOFBOUND; index = (front+k-1)%N; // index of the element to be deleted. for( i=k+1; i<=nelem; ++i ) clist[ (front+i-2)%N ] = clist[ (front+i-1)%N ]; if( nelem == 1 ) // list is empty now. front = ILLEGALINDEX; else if( k == 1 ) front = (front+1)%N; else rear = (rear-1+N)%N; return SUCCESS; } int lInsertAfterK( type data, int k ) { /* * inserts 'data' after k'th element in the list. * if list is full or k is out of bounds, error is returned. * k starts from 0. */ int i, index; int nelem = lGetNElements(); printf( "inserting %d after %d'th element... ", data, k ); if( k > nelem || k < 0 || nelem == N ) return EINDEXOUTOFBOUND; if( nelem == 0 ) // list empty. front = rear = FIRSTINDEX; else rear = (rear+1)%N; index = (front+k)%N; // index at which data should be inserted. for( i=nelem; i>k; -i ) clist[ (front+i)%N ] = clist[ (front+i-1)%N ]; clist[ (front+k)%N ] = data; } int main() { lInsertAfterK(100,0); lPrint(); lPush(0); lPush(4); lPush(7); lPush(1); lPush(13); lPush(2); lPush(5); lPrint(); lInsertAfterK(2,1); lPrint(); lDeleteK(4); lPrint(); lPush(6); lPush(3); lPush(23); lPrint(); lDeleteK(9); lPrint(); lInsertAfterK(20,9); lPrint(); lDeleteK(10); lPrint(); lInsertAfterK(20,0); lPrint(); return 0; }
Explanation
If k == 5, then after lDeleteK() runs, the queue looks like this:
Note that elements 6 and 7 have been shifted back by one position.
Then, after lInsertAfterK() is run with k == 4, the queue becomes
Note how the rear is wrapped around.
Points to Remember
Write a function for a singly linked circular list that reverses the direction of the links.
Program
#include #define SUCCESS 0 #define ERROR -1 typedef int type; typedef struct node node; struct node { type data; node *next; }; node *head = NULL; int lInsert( type data ) { /* * inserts a new node containing data at start of the list. */ node *ptr = (node *)malloc( sizeof(node) ); ptr->data = data; if( head == NULL ) { // this is the first element in the list. ptr->next = ptr; head = ptr; } else { ptr->next = head->next; head->next = ptr; } return SUCCESS; } void lPrint() { node *ptr; if( head == NULL ) return; else printf( "%d ", head->data ); for( ptr=head->next; ptr!=head; ptr=ptr->next ) printf( "%d ", ptr->data ); printf( " " ); } int lReverse() { /* * insitu reverses the list. */ node *curr, *prev, *next; printf( "reversing list... " ); if( head == NULL ) return SUCCESS; for( prev=head, curr=prev->next, next=curr->next; curr!=head; prev=curr, curr=next, next=next->next ) { curr->next = prev; } head->next = prev; return SUCCESS; } int main() { lPrint(); lInsert(1); lPrint(); lInsert(2); lInsert(3); lInsert(4); lInsert(5); lInsert(6); lPrint(); lReverse(); lPrint(); return 0; }
Explanation
After reversal this list appears as shown here:
Points to Remember
Design a storage management scheme where all requests for memory are of the same size, say K. Write functions to free and allocate storage in this scheme.
Program
#include #define N 90 #define K 10 #define SUCCESS 0 #define ERROR -1 typedef struct node node; struct node { void *ptr; // points to free block of size K. node *next; }; struct head { //int nnodes; node *next; char *bytes; // mem will be allocated from this pool. }freelist; void init() { /* * initialize the memory space. */ int i; void memfree( void * ); //freelist.nnodes = 0; freelist.next = NULL; freelist.bytes = (char *)malloc(N); for( i=N/K-1; i>=0; -i ) { memfree( freelist.bytes+K*i ); } } void *memalloc() { // assume request to be of size K. /* * returns a void * pointer to area from freelist. */ void *ptr; node *nodeptr; if( freelist.next == NULL ) return (void *)NULL; nodeptr = freelist.next; ptr = nodeptr->ptr; freelist.next = freelist.next->next; free(nodeptr); // this is standard free(). return ptr; } void memfree( void *ptr ) { /* * adds ptr to freelist. */ node *nodeptr; if( ptr == NULL ) return; nodeptr = (node *)malloc( sizeof(node) ); nodeptr->ptr = ptr; nodeptr->next = freelist.next; freelist.next = nodeptr; } void print() { node *ptr; for( ptr=freelist.next; ptr!=NULL; ptr=ptr->next ) { printf( "%u ", ptr->ptr ); } printf( " " ); } int main() { void *p1, *p2, *p3, *p4; init(); printf( "after init... " ); print(); p1 = memalloc(); printf( "after memalloc(p1)... " ); p2 = memalloc(); p3 = memalloc(); print(); memfree(p1); memfree(p2); memfree(p3); printf( "after memfree(p1)... " ); print(); return 0; }
Explanation
Implement a memory allocation scheme by using the algorithms first-fit, next-fit, and best-fit.
Program
#include #define N 100 typedef struct node node; typedef enum {FALSE, TRUE} bool; struct node { char *ptr; // start addr. int size; // size of the free block. node *next; // next free block. }; char mem[N]; // total memory pool. node freelist; /* * the freelist should be sorted on start addr. * this will ease coalescing adjacent blocks. */ void init() { /* * init freelist to contain the whole mem. */ node *ptr = (node *)malloc( sizeof(node) ); ptr->ptr = mem; ptr->size = N; ptr->next = NULL; freelist.next = ptr; } void removenode( node *ptr, node *prev ) { /* * remove a node ptr from the list whose previous node is prev. */ prev->next = ptr->next; free(ptr); } char *firstfit( int size ) { * * returns ptr to free pool of size size from freelist. */ node *ptr, *prev; char *memptr; for( prev=&freelist, ptr=prev->next; ptr; prev=ptr, ptr=ptr->next ) if( ptr->size > size ) { memptr = ptr->ptr; ptr->size -= size; ptr->ptr += size; return memptr; } else if( ptr->size == size ) { memptr = ptr->ptr; removenode( ptr, prev ); return memptr; } return NULL; } char *nextfit( int size ) { /* * returns ptr to free pool of size size from freelist. * the free pool is second allocatable block instead of first. * if no second block then first is returned. */ bool isSecond = FALSE; node *prev, *ptr; node *firstprev, *firstptr; for( prev=&freelist, ptr=prev->next; ptr; prev=ptr, ptr=ptr->next ) if( ptr->size >= size && isSecond == FALSE ) { isSecond = TRUE; firstprev = prev; firstptr = ptr; } else if( ptr->size > size && isSecond == TRUE ) { char *memptr = ptr->ptr; ptr->size -= size; ptr->ptr += size; return memptr; } else if( ptr->size == size && isSecond == TRUE ) { char *memptr = ptr->ptr; removenode( ptr, prev ); return memptr; } // ptr is NULL. ptr = firstptr; prev = firstprev; if( ptr->size > size && isSecond == TRUE ) { char *memptr = ptr->ptr; ptr->size -= size; ptr->ptr += size; return memptr; } else if( ptr->size == size && isSecond == TRUE ) { char *memptr = ptr->ptr; removenode( ptr, prev ); return memptr; } else // isSecond == FALSE return NULL; } char *bestfit( int size ) { /* * returns ptr to free pool of size size from freelist. * the allocated block's original size - size is min in the freelist. */ node *ptr, *prev; char *memptr; int minwaste = N+1; node *minptr = NULL, *minprev; for( prev=&freelist, ptr=prev->next; ptr; prev=ptr, ptr=ptr->next ) if( ptr->size >= size && ptr->size-size < minwaste ) { minwaste = ptr->size-size; minptr = ptr; minprev = prev; } if( minptr == NULL ) // could NOT get any allocatable mem. return NULL; ptr = minptr; prev = minprev; if( ptr->size > size ) { memptr = ptr->ptr; ptr->size -= size; ptr->ptr += size; return memptr; } else if( ptr->size == size ) { memptr = ptr->ptr; removenode( ptr, prev ); return memptr; } return NULL; } void addtofreelist( char *memptr, int size ) { /* * add memptr of size to freelist. * remember that block ptrs are sorted on mem addr. */ node *prev, *ptr, *newptr; for( prev=&freelist, ptr=prev->next; ptr && ptr->ptrnext ) ; // memptr is to be added between prev and ptr. newptr = (node *)malloc( sizeof(node) ); newptr->ptr = memptr; newptr->size = size; newptr->next = ptr; prev->next = newptr; } void coalesce() { /* * combine adj blocks of list if necessary. */ node *prev, *ptr; for( prev=&freelist, ptr=prev->next; ptr; prev=ptr, ptr=ptr->next ) // check for prev mem addr and size against ptr->ptr. if( prev != &freelist && prev->ptr+prev->size == ptr->ptr ) {// prev->size += ptr->size; // prev->next = ptr->next; free(ptr); ptr = prev; // ). } } char *memalloc( int size ) { /* * return ptr to pool of mem of the size. * return NULL if NOT available. * ptr-sizeof(int) contains size of the pool allocated, like malloc. */ char *ptr = bestfit( size+sizeof(int) ); // change this to firstfit() or nextfit(). printf( "allocating %d using bestfit... ", size ); if( ptr == NULL ) return NULL; *(int *)ptr = size; return ptr+sizeof(int); } void memfree( char *ptr ) { /* * adds ptr to freelist and combine adj blocks if necessary. * size of the mem being freed is at ptr-sizeof(int). */ int size = *(int *)(ptr-sizeof(int)); printf( "freeing %d... ", size ); addtofreelist( ptr-sizeof(int), size+sizeof(int) ); coalesce(); // combine adjacent blocks. } void printfreelist() { node *ptr; printf( " " ); for( ptr=freelist.next; ptr; ptr=ptr->next ) printf( "{%u %d} ", ptr->ptr, ptr->size ); printf( " " ); } int main() { char *p1, *p2, *p3, *p4, *p5; init(); printfreelist(); p1 = memalloc(10); printfreelist(); p2 = memalloc(15); printfreelist(); p3 = memalloc(23); printfreelist(); p4 = memalloc(3); printfreelist(); p5 = memalloc(8); printfreelist(); memfree(p1); printfreelist(); memfree(p5); printfreelist(); memfree(p3); printfreelist(); p1 = memalloc(23); printfreelist(); p1 = memalloc(23); printfreelist(); memfree(p2); printfreelist(); p1 = memalloc(3); printfreelist(); memfree(p4); printfreelist(); p2 = memalloc(1); printfreelist(); memfree(p1); printfreelist(); memfree(p2); printfreelist(); return 0; }
Explanation
Points to Remember
Implement a mark() procedure used in garbage collection to mark all the nodes traversible from a head node by using a stack.
Program
/************************ mark1.s.c **************************/ #include typedef struct snode snode; typedef list stype; typedef struct snode *stack; struct snode { stype op; snode *next; }; bool sEmpty( stack *s ) { return (*s == NULL); } void sPush( stack *s, stype op ) { /* * pushes op in stack s. */ snode *ptr = (snode *)malloc( sizeof(snode) ); ptr->op = op; ptr->next = *s; *s = ptr; } stype sTop( stack *s ) { /* * returns top op from stack s without popping. */ if( sEmpty(s) ) return NULL; return (*s)->op; } stype sPop( stack *s ) { /* * pops op from top of stack s. */ snode *ptr = *s; stype op; if( sEmpty(s) ) return NULL; *s = (*s)->next; op = ptr->op; free(ptr); return op; } /************************ mark1.c ***************************/ #include typedef struct node node; typedef int type; typedef enum {FALSE, TRUE} bool; typedef node *list; #include "mark1.s.c" struct node { bool mark; type val; node *horiz; node *vert; }; list newNode() { /* * return a new node. */ return (list)calloc(1, sizeof(node)); } list createList() { /* * return a dummy list created. */ list ptr; snode *s = NULL; list sixptr; list nineptr; ptr = newNode(); sPush(&s, ptr); ptr->val = 1; ptr->horiz = newNode(); ptr = ptr->horiz; sPush(&s, ptr); ptr->val = 2; ptr->vert = newNode(); ptr = ptr->vert; sPush(&s, ptr); ptr->val = 3; ptr->vert = newNode(); ptr = ptr->vert; ptr->val = 4; ptr = sPop(&s); ptr->horiz = newNode(); ptr = ptr->horiz; ptr->val = 5; ptr->horiz = newNode(); ptr = ptr->horiz; sPush(&s, ptr); sixptr = ptr; ptr->val = 6; ptr->vert = newNode(); ptr = ptr->vert; ptr->val = 7; ptr = sPop(&s); ptr->horiz = newNode(); ptr = ptr->horiz; ptr->val = 8; ptr = sPop(&s); ptr->horiz = newNode(); ptr = ptr->horiz; sPush(&s, ptr); nineptr = ptr; ptr->val = 9; ptr->vert = newNode(); ptr = ptr->vert; ptr->val = 10; ptr->horiz = newNode(); ptr = ptr->horiz; ptr->val = 11; ptr = sPop(&s); ptr->horiz = newNode(); ptr = ptr->horiz; ptr->vert = nineptr; // an internal link. ptr->val = 12; ptr->horiz = newNode(); ptr = ptr->horiz; sPush(&s, ptr); ptr->val = 13; ptr->vert = newNode(); ptr = ptr->vert; ptr->val = 14; ptr->horiz = sixptr; // an internal link. ptr = sPop(&s); return sPop(&s); } void markList(list ptr) { /* * print the horiz and vert lists iteratively using a stack. */ snode *s = NULL; list horiz; if(!ptr || ptr->mark) return; ptr->mark = TRUE; printf("marked=%d. ", ptr->val); sPush(&s, ptr); while(!sEmpty(&s)) { ptr = sPop(&s); do { horiz = ptr->horiz; if(horiz && horiz->mark == FALSE) { horiz->mark = TRUE; printf("marked=%d. ", horiz->val); sPush(&s, horiz); } ptr = ptr->vert; if(!ptr || ptr->mark) break; ptr->mark = TRUE; printf("marked=%d. ", ptr->val); } while(TRUE); } } void markListRec(list ptr) { /* * mark the list pointed to by ptr recursively. */ for(; ptr && !ptr->mark; ptr=ptr->horiz) { ptr->mark = TRUE; printf("marked=%d. ", ptr->val); markListRec(ptr->vert); } } int main() { list head = createList(); markListRec(head); return 0; }
struct node { bool mark; type val; node *horiz; node *vert; };
Thus the lists are generalized and can grow in both horizontal and vertical directions.
markListRec(ptr) { for(; ptr && !ptr->mark; ptr=ptr->horiz) { ptr->mark = TRUE; markListRec(ptr->vert); } }
This procedure uses the system stack for recursion (internally).
Different steps of the algorithm:
STEP |
PTR |
PTR->MARK |
HORIZ |
HORIZ->MARK |
STACK |
OUTPUT |
---|---|---|---|---|---|---|
0 |
1 |
F |
— |
— |
1 |
1 |
1 |
1 |
T |
2 |
F |
2 |
1 2 |
2 |
2 |
T |
9 |
F |
9 |
1 2 9 |
3 |
3 |
F |
9 |
T |
9 |
1 2 9 3 |
4 |
3 |
T |
5 |
F |
9 5 |
1 2 9 3 5 |
5 |
4 |
F |
5 |
T |
9 5 |
1 2 9 3 5 4 |
6 |
5 |
T |
6 |
F |
9 6 |
1 2 9 3 5 4 6 |
7 |
6 |
T |
8 |
F |
9 8 |
1 2 9 3 5 4 6 |
8 |
7 |
F |
8 |
T |
9 8 |
1 2 9 3 5 4 6 8 7 |
9 |
8 |
T |
nil |
— |
9 |
1 2 9 3 5 4 6 8 7 |
10 |
9 |
T |
12 |
F |
12 |
1 2 9 3 5 4 6 8 7 12 |
11 |
10 |
F |
12 |
F |
12 |
1 2 9 3 5 4 6 8 7 12 10 |
12 |
10 |
T |
11 |
F |
12 11 |
1 2 9 3 5 4 6 8 7 12 10 11 |
13 |
11 |
T |
11 |
T |
12 |
1 2 9 3 5 4 6 8 7 12 10 11 |
14 |
12 |
T |
13 |
F |
13 |
1 2 9 3 5 4 6 8 7 12 10 11 13 |
15 |
9 |
T |
13 |
T |
13 |
1 2 9 3 5 4 6 8 7 12 10 11 13 |
16 |
13 |
T |
nil |
— |
empty |
1 2 9 3 5 4 6 8 7 12 10 11 13 |
17 |
14 |
F |
6 |
T |
empty |
1 2 9 3 5 4 6 8 7 12 10 11 13 14 |
18 |
14 |
T |
6 |
T |
empty |
1 2 9 3 5 4 6 8 7 12 10 11 13 14 |
Thus in each step, the horizontal node is pushed as the return point and the whole vertical list is traversed. The return point is then popped and the procedure is continued until the stack becomes empty.
In step 9, since 8 is already marked, nothing is output. In step 14, ptr points to 12, which is marked, and horiz points to 13, which is unmarked. Thus it marks 13 and pushes it on stack. In the next step, the vertical list is traversed and ptr points to 9 while horiz is still 13. Since 9 is already marked, it is left and 13 is popped. horiz is now nil. Now the vertical list of 13 is traversed and ptr points to 14, which is unmarked, and so is marked. horiz now points to 6, which is marked, so nothing is done to it. A vertical pointer of 14 is traversed and it is found to be nil, so the inner loop quits. The stack is empty at this point, so the outer loop also quits and the procedure terminates.
Points to Remember
Implement the marking procedure used in garbage collection without using more than a constant amount of memory.
Program
/************************ mark2.s.c *************************/ #include typedef struct snode snode; typedef list stype; typedef struct snode *stack; struct snode { stype op; snode *next; }; bool sEmpty( stack *s ) { return (*s == NULL); } void sPush( stack *s, stype op ) { /* * pushes op in stack s. */ snode *ptr = (snode *)malloc( sizeof(snode) ); ptr->op = op; ptr->next = *s; *s = ptr; } stype sTop( stack *s ) { /* * returns top op from stack s without popping. */ if( sEmpty(s) ) return NULL; return (*s)->op; } stype sPop( stack *s ) { /* * pops op from top of stack s. */ snode *ptr = *s; stype op; if( sEmpty(s) ) return NULL; *s = (*s)->next; op = ptr->op; free(ptr); return op; } /************************ mark2.c ***************************/ #include typedef struct node node; typedef int type; typedef enum {FALSE, TRUE} bool; typedef node *list; struct node { bool mark; bool tag; type val; node *horiz; node *vert; }; #include "mark2.s.c" list newNode() { /* * return a new node. */ list ptr = (list)calloc(1, sizeof(node)); return ptr; } list createList() { /* * return a dummy list created. */ list ptr; snode *s = NULL; list sixptr; list nineptr; ptr = newNode(); sPush(&s, ptr); ptr->val = 1; ptr->horiz = newNode(); ptr = ptr->horiz; sPush(&s, ptr); ptr->val = 2; ptr->vert = newNode(); ptr = ptr->vert; sPush(&s, ptr); ptr->val = 3; ptr->vert = newNode(); ptr = ptr->vert; ptr->val = 4; ptr = sPop(&s); ptr->horiz = newNode(); ptr = ptr->horiz; ptr->val = 5; ptr->horiz = newNode(); ptr = ptr->horiz; sPush(&s, ptr); sixptr = ptr; ptr->val = 6; ptr->vert = newNode(); ptr = ptr->vert; ptr->val = 7; ptr = sPop(&s); ptr->horiz = newNode(); ptr = ptr->horiz; ptr->val = 8; ptr = sPop(&s); ptr->horiz = newNode(); ptr = ptr->horiz; sPush(&s, ptr); nineptr = ptr; ptr->val = 9; ptr->vert = newNode(); ptr = ptr->vert; ptr->val = 10; ptr->horiz = newNode(); ptr = ptr->horiz; ptr->val = 11; ptr = sPop(&s); ptr->horiz = newNode(); ptr = ptr->horiz; ptr->vert = nineptr; // an internal link. ptr->val = 12; ptr->horiz = newNode(); ptr = ptr->horiz; sPush(&s, ptr); ptr->val = 13; ptr->vert = newNode(); ptr = ptr->vert; ptr->val = 14; ptr->horiz = sixptr; // an internal link. ptr = sPop(&s); return sPop(&s); } void markList(list ptr) { /* * print the horiz and vert lists iteratively without using a stack. */ list p, q, t; p = ptr; t = NULL; do { printf("p->val=%d. ", p->val); q = p->vert; if(q) if(q->mark == FALSE && q->tag == FALSE) { q->mark = TRUE; p->tag = TRUE; p->vert = t; t = p; p = q; } else { q->mark = TRUE; label: q = p->horiz; if(q) if(q->mark == FALSE && q->tag == FALSE) { q->mark = TRUE; p->horiz = t; t = p; p = q; } else { q->mark = TRUE; label2: while(t) { q = t; if(q->tag) { t = q->vert; q->vert = p; q->tag = FALSE; p = q; goto label; } t = q->horiz; q->horiz = p; p = q; } } else goto label2; } else goto label; } while(t); } int main() { list head = createList(); markList(head); return 0; }
Explanation
struct node { bool mark; bool tag; type val; node *horiz; node *vert; };
Thus, using horiz and vert, generalized lists can be created containing data in val. mark is used for marking the nodes as visited or not. An additional Boolean tag is needed since we are not using an extra amount of memory in the algorithm, except for a few pointers. The mark and tag fields are initially FALSE for each node.
The explicit stack is used for creating the list (createList()), not for marking the nodes.
Initially, all nodes except node A are unmarked. From A we can move down to B or right to I. This algorithm always moves down when faced with such an alternative. We use p to point to the node currently being examined and t to point to the node preceding p in the path from ptr to p. The path t to ptr will be examined as a chain composed of the nodes on this t – ptr (read as "t to ptr") path. If we advance from node p to node q, then either q=p->horiz or q=p->vert, and q will become the node currently being examined. The node preceding q on the ptr–q path is p, and so the path list must be updated to represent the path from p to ptr. This is done simply by adding the node p to the t–ptr path that has been already constructed. Nodes will be linked onto this path through either their vert or horiz field. When node p is added to the path chain, p is linked to t via its vert field, if q=p->vert. When q=p->horiz, p is linked to t via its horiz field. In order to be able to determine whether a node on the t–ptr path list is linked through either the vert or horiz field, we make use of the tag field. When vert is used for linking, this tag will be TRUE. Thus, for nodes on t–ptr path we have:
tag = FALSE if the node is linked via horiz field. = TRUE if the node is linked via vert field.
The tag will be reset to FALSE when the node gets off the t–ptr path list. Different snapshots of the list are shown here:
At the end of the algorithm, all the nodes are marked and all tag fields are restored to FALSE. Thus the list looks like this.
Points to Remember
Write a program to produce N equivalent classes as linked lists from a linked list of integers, applying the mod function.
Program
#include typedef struct node node; struct node { int val; node *next; }; node *getList(int a[], int n) { /* * form a list of n integers in a[]. */ int i; node *list = NULL; for( i=0; ival = a[i]; ptr->next = list; list = ptr; } return list; } node **applyMod(node *list, int n) { /* * apply (mod n) on every element of list and store that element in * the list modlists[(mod n)]. * thus we form array[n] of lists. * each list is one equivalence class. */ node **modlists; node *ptr, *next; modlists = (node **)calloc( n, sizeof(node *) ); for(ptr=list, next=(ptr?ptr->next:NULL); ptr; ptr=next, next=(next?next->next:NULL)) ptr->next = modlists[ptr->val%n], modlists[ptr->val%n] = ptr; return modlists; } void printModlists(node **modlists, int n) { /* * prints the equivalence classes. */ node *ptr; int i; for(i=0; inext) printf("%d ", ptr->val); printf(" "); } printf(" "); } main() { int a[] = {10,2,3,44,432,35,6576,34,12,5456,23423,234,23}; node *list = getList(a, sizeof(a)/sizeof(int)); node **modlists; int n; printf( "Enter number of equivalence classes: " ); scanf( "%d", &n ); modlists = applyMod(list, n); printModlists(modlists, n); return 0; }
Explanation
Points to Remember
Part I - C Language
Part II - Data Structures
Part III - Advanced Problems in Data Structures