home *** CD-ROM | disk | FTP | other *** search
- /* topological sort
- * input is sequence of pairs of items (blank-free strings)
- * nonidentical pair is a directed edge in graph
- * identical pair merely indicates presence of node
- * output is ordered list of items consistent with
- * the partial ordering specified by the graph
- */
- #include "stdio.h"
-
- /* the nodelist always has an empty element at the end to
- * make it easy to grow in natural order
- */
-
- struct nodelist {
- struct nodelist *nextnode;
- struct predlist *inedges;
- char *name;
- enum {DEAD, LIVE, ONCE, TWICE} live;
- } firstnode = {NULL, NULL, NULL, DEAD};
-
- /* a predecessor list tells all the immediate
- * predecessors of a given node
- */
- struct predlist {
- struct predlist *nextpred;
- struct nodelist *pred;
- };
-
- struct nodelist *index();
- struct nodelist *findloop();
- struct nodelist *mark();
- char *malloc();
- char *empty = "";
-
- /* the first for loop reads in the graph,
- * the second prints out the ordering
- */
- main(argc,argv)
- char **argv;
- {
- register struct predlist *t;
- FILE *input = stdin;
- register struct nodelist *i, *j;
- int x;
- char precedes[50], follows[50];
- if(argc>1) {
- input = fopen(argv[1],"r");
- if(input==NULL)
- error("cannot open ", argv[1]);
- }
- for(;;) {
- x = fscanf(input,"%s%s",precedes, follows);
- if(x==EOF)
- break;
- if(x!=2)
- error("odd data",empty);
- i = index(precedes);
- j = index(follows);
- if(i==j||present(i,j))
- continue;
- t = (struct predlist *)malloc(sizeof(struct predlist));
- t->nextpred = j->inedges;
- t->pred = i;
- j->inedges = t;
- }
- for(;;) {
- x = 0; /*anything LIVE on this sweep?*/
- for(i= &firstnode; i->nextnode!=NULL; i=i->nextnode) {
- if(i->live==LIVE) {
- x = 1;
- if(!anypred(i))
- break;
- }
- }
- if(x==0)
- break;
- if(i->nextnode==NULL)
- i = findloop();
- printf("%s\n",i->name);
- i->live = DEAD;
- }
- }
-
- /* is i present on j's predecessor list?
- */
- present(i,j)
- struct nodelist *i, *j;
- {
- register struct predlist *t;
- for(t=j->inedges; t!=NULL; t=t->nextpred)
- if(t->pred==i)
- return(1);
- return(0);
- }
-
- /* is there any live predecessor for i?
- */
- anypred(i)
- struct nodelist *i;
- {
- register struct predlist *t;
- for(t=i->inedges; t!=NULL; t=t->nextpred)
- if(t->pred->live==LIVE)
- return(1);
- return(0);
- }
-
- /* turn a string into a node pointer
- */
- struct nodelist *
- index(s)
- register char *s;
- {
- register struct nodelist *i;
- register char *t;
- for(i= &firstnode; i->nextnode!=NULL; i=i->nextnode)
- if(cmp(s,i->name))
- return(i);
- for(t=s; *t; t++) ;
- t = malloc((unsigned)(t+1-s));
- i->nextnode = (struct nodelist *)malloc(sizeof(struct nodelist));
- if(i->nextnode==NULL||t==NULL)
- error("too many items",empty);
- i->name = t;
- i->live = LIVE;
- i->nextnode->nextnode = NULL;
- i->nextnode->inedges = NULL;
- i->nextnode->live = DEAD;
- while(*t++ = *s++);
- return(i);
- }
-
- cmp(s,t)
- register char *s, *t;
- {
- while(*s==*t) {
- if(*s==0)
- return(1);
- s++;
- t++;
- }
- return(0);
- }
-
- error(s,t)
- char *s, *t;
- {
- note(s,t);
- exit(1);
- }
-
- note(s,t)
- char *s,*t;
- {
- fprintf(stderr,"tsort: %s%s\n",s,t);
- }
-
- /* given that there is a cycle, find some
- * node in it
- */
- struct nodelist *
- findloop()
- {
- register struct nodelist *i, *j;
- register struct predlist *p;
- for(i= &firstnode; i->nextnode!=NULL; i=i->nextnode)
- if(i->live==LIVE)
- break;
- note("cycle in reverse order",empty);
- while(i->live==LIVE) {
- i->live = ONCE;
- for(p=i->inedges; ; p=p->nextpred) {
- if(p==NULL)
- error("error 1");
- i = p->pred;
- if(i->live!=DEAD)
- break;
- }
- }
- while(i->live==ONCE) {
- i->live = TWICE;
- note(i->name,empty);
- for(p=i->inedges; ; p=p->nextpred) {
- if(p==NULL)
- error("error 2");
- i = p->pred;
- if(i->live!=DEAD)
- break;
- }
- }
- for(j= &firstnode; j->nextnode!=NULL; j=j->nextnode)
- if(j->live!=DEAD)
- j->live = LIVE;
- return(i);
- }
-
-