/* Steven Andrews, 4/20/95, modified 9/98, modified 1/21/02 */ /* Performs basic set operations with an unordered linked list */ /* See documentation called Set doc */ /* Copyright 2003 by Steven Andrews. Permission is granted for non-commercial use of and modifications to the code. */ #include #include "Set.h" int FindCell(void *k,void *x,set s,struct scell **prevptr,struct scell **cellptr); int FindKey(void *k,set s,struct scell **prevptr,struct scell **cellptr); int FindItem(void *x,set s,struct scell **prevptr,struct scell **cellptr); struct scell *SetCellAlloc(); void SetCellFree(struct scell *cell,int freek,int freex); struct scell *SetCellAlloc() { struct scell *cell; cell=(struct scell *) malloc(sizeof(struct scell)); if(!cell) return NULL; cell->key=NULL; cell->item=NULL; cell->next=NULL; return cell; } void SetCellFree(struct scell *cell,int freek,int freex) { if(!cell) return; if(freek&&cell->key) free(cell->key); if(freex&&cell->item) free(cell->item); free(cell); return; } int FindCell(void *k,void *x,set s,struct scell **prevptr,struct scell **cellptr) { /* If not in set, returns 0, prev points to last filled cell if any, cell points to final empty cell. */ /* If in set, returns 1 and prev points before or NULL if none before, cell points to member. */ struct scell *c; *prevptr=NULL; *cellptr=c=s->list; while(c->next&&(s->keycmp&&(*s->keycmp)(k,c->key)||s->itemcmp&&(*s->itemcmp)(x,c->item))) { *prevptr=c; *cellptr=c=c->next; } if(c->next) return 1; return 0; } int FindKey(void *k,set s,struct scell **prevptr,struct scell **cellptr) { /* See FindCell */ struct scell *c; *prevptr=NULL; *cellptr=c=s->list; if(!s->keycmp) return 0; while(c->next&&(*s->keycmp)(k,c->key)) { *prevptr=c; *cellptr=c=c->next; } if(c->next) return 1; return 0; } int FindItem(void *x,set s,struct scell **prevptr,struct scell **cellptr) { /* See FindCell */ struct scell *c; *prevptr=NULL; *cellptr=c=s->list; if(!s->itemcmp) return 0; while(c->next&&(*s->itemcmp)(x,c->item)) { *prevptr=c; *cellptr=c=c->next; } if(c->next) return 1; return 0; } set SetAlloc(int (*keycmp)(void *,void *),int (*itemcmp)(void *,void *)) { set s; if(!keycmp&&!itemcmp) return NULL; s=(set) malloc(sizeof(struct sstruct)); if(!s) return NULL; s->keycmp=keycmp; s->itemcmp=itemcmp; s->list=SetCellAlloc(); if(!s->list) {SetFree(s,0,0);return NULL;} return s; } void SetFree(set s,int freek,int freex) { if(!s) return; if(s->list) { SetNull(s,freek,freex); SetCellFree(s->list,freek,freex); } free(s); } void SetNull(set s,int freek,int freex) { struct scell *cell,*prev; cell=s->list; while(cell->next) { prev=cell; cell=cell->next; SetCellFree(prev,freek,freex); } s->list=cell; } int SetInsert(void *k,void *x,set s) { struct scell *cell,*prev,*cz; int i; i=FindCell(k,x,s,&prev,&cell); if(i) return 2; if(!prev) { prev=SetCellAlloc(); if(!prev) return 0; s->list=prev; } else { cz=SetCellAlloc(); if(!cz) return 0; prev->next=cz; prev=cz; } prev->key=k; prev->item=x; prev->next=cell; return 1; } int SetDelete(void *k,void *x,set s,int freek,int freex) { struct scell *cell,*prev; int i; i=FindCell(k,x,s,&prev,&cell); if(!i) return 0; if(!prev) s->list=cell->next; else prev->next=cell->next; SetCellFree(cell,freek,freex); return 1; } int SetMember(void *k,void *x,set s) { struct scell *cell,*prev; return FindCell(k,x,s,&prev,&cell); } void *SetItem(void *k,set s) { struct scell *cell,*prev; return(FindKey(k,s,&prev,&cell)?cell->item:0); } void **SetItemAt(void *k,set s) { struct scell *cell,*prev; return(FindKey(k,s,&prev,&cell)?&(cell->item):0); } void *SetKey(void *x,set s) { struct scell *cell,*prev; return(FindItem(x,s,&prev,&cell)?cell->key:0); } struct scell *SetNext(struct scell *ptr,void **k,void **x,set s) { if(!ptr) ptr=s->list; *k=ptr->key; *x=ptr->item; ptr=ptr->next; return ptr; } int Subset(set s1,set s2) { struct scell *cell1,*cell2,*prev2; cell1=s1->list; while(cell1->next&&FindCell(cell1->key,cell1->item,s2,&cell2,&prev2)) cell1=cell1->next; return(cell1->next)?0:1; } int SetEqual(set s1,set s2) { return(Subset(s1,s2)&&Subset(s2,s1))?1:0; } set SetUnion(set s1,set s2) { struct scell *cell; set s3; int ok; s3=SetAlloc(s1->keycmp,s1->itemcmp); if(!s3) return 0; ok=1; for(cell=s1->list;ok&&cell->next;cell=cell->next) ok=SetInsert(cell->key,cell->item,s3); for(cell=s2->list;ok&&cell->next;cell=cell->next) ok=SetInsert(cell->key,cell->item,s3); if(!ok) {SetFree(s3,0,0);return 0;} return s3; } set SetIntersect(set s1,set s2) { struct scell *cell,*cell2,*prev2; set s3; int ok; s3=SetAlloc(s1->keycmp,s1->itemcmp); if(!s3) return 0; ok=1; for(cell=s1->list;ok&&cell->next;cell=cell->next) if(FindCell(cell->key,cell->item,s2,&prev2,&cell2)) ok=SetInsert(cell->key,cell->item,s3); if(!ok) {SetFree(s3,0,0);return 0;} return s3; } set SetDiff(set s1,set s2) { struct scell *cell,*cell2,*prev2; set s3; int ok; s3=SetAlloc(s1->keycmp,s1->itemcmp); if(!s3) return 0; ok=1; for(cell=s1->list;ok&&cell->next;cell=cell->next) if(!FindCell(cell->key,cell->item,s2,&prev2,&cell2)) ok=SetInsert(cell->key,cell->item,s3); if(!ok) {SetFree(s3,0,0);return 0;} return s3; } int SetCard(set s) { struct scell *cell; int i=0; for(cell=s->list;cell->next;cell=cell->next) i++; return i; }