📄 tsort.c
字号:
/* topo - topological sort Author: Kent Williams *//*** topo - perform a topological sort of the output of lorder.**** Usage : topo [infile] [outfile]**** Author: Kent Williams (williams@umaxc.weeg.uiowa.edu)*/#include <ctype.h>#include <stdlib.h>#include <string.h>#include <stdio.h>typedef struct __v { struct __v *next; /* link list node */ int indegree, /* number of edges into this vertex */ visited, /* depth-first search visited flag */ on_the_path, /* used to find cycles */ has_a_cycle; /* true if a cycle at this vertex */ struct __e *out; /* outgoing edges from this vertex */ char key[1]; /* name of this vertex */} vertex;typedef struct __e { struct __e *next; /* link list node */ vertex *v; /* vertex to which this edge goes */} edge;_PROTOTYPE(int main, (int argc, char **argv));_PROTOTYPE(void *xmalloc, (size_t siz));_PROTOTYPE(edge *new_edge, (vertex *v));_PROTOTYPE(char *copyupto, (char *name, char *buf, int stop));_PROTOTYPE(int child_of, (vertex *parent, vertex *child));_PROTOTYPE(vertex *add_v, (char *s));_PROTOTYPE(void readin, (void));_PROTOTYPE(void pushname, (char *s));_PROTOTYPE(char *popname, (void));_PROTOTYPE(void topo, (void));_PROTOTYPE(void print_cycle, (vertex *parent, vertex *child));_PROTOTYPE(void dfs, (vertex *v));_PROTOTYPE(void check_cycles, (void));/*** xmalloc -- standard do or die malloc front end.*/void *xmalloc(siz)size_t siz;{ void *rval = (void *)malloc(siz); if(rval == NULL) { fputs("Out of memory.\n",stderr); exit(1); } return rval;}/*** edge allocater.*/edge *new_edge(v)vertex *v;{ edge *rval; rval = (edge *)xmalloc(sizeof(edge)); rval->v = v; return rval;}/*** copyupto - copy until you see the stop character.*/char *copyupto(name,buf,stop)char *name,*buf,stop;{ while(*buf != '\0' && *buf != stop) *name++ = *buf++; *name = '\0'; while(*buf != '\0' && isspace(*buf)) buf++; return buf;}/*** find out if the vertex child is a child of the vertex parent.*/intchild_of(parent,child)vertex *parent,*child;{ edge *e; for(e = parent->out; e != NULL && e->v != child; e = e->next) ; return e == NULL ? 0 : 1;}/*** the vertex set.**** add_v adds a vertex to the set if it's not already there.*/vertex *vset = NULL;vertex *add_v(s)char *s;{ vertex *v,*last; /* ** go looking for this key in the vertex set. */ for(last = v = vset; v != NULL && strcmp(v->key,s) != 0; last = v, v = v->next) ; if(v != NULL) { /* ** use the move-to-front heuristic to keep this from being ** an O(N^2) algorithm. */ if(last != vset) { last->next = v->next; v->next = vset; vset = v; } return v; } v = (vertex *)xmalloc(sizeof(vertex) + strlen(s)); v->out = NULL; strcpy(v->key,s); v->indegree = v->on_the_path = v->has_a_cycle = v->visited = 0; v->next = vset; vset = v; return v;}/*** readin -- read in the dependency pairs.*/voidreadin(){ static char buf[128]; static char name[64]; char *bp; vertex *child,*parent; edge *e; while(gets(buf) != NULL) { bp = copyupto(name,buf,' '); child = add_v(name); parent = add_v(bp); if(child != parent && !child_of(parent,child)) { e = new_edge(child); e->next = parent->out; parent->out = e; child->indegree++; } }}/*** the topological sort produces names of modules in reverse of** the order we want them in, so use a stack to hold the names** until we get them all, then pop them off to print them.*/struct name { struct name *next; char *s; }*namelist = NULL;voidpushname(s)char *s;{ struct name *x = (struct name *)xmalloc(sizeof(struct name)); x->s = s; x->next = namelist; namelist = x;}char *popname() { char *rval; struct name *tmp; if(namelist == NULL) return NULL; tmp = namelist; rval = namelist->s; namelist = namelist->next; free(tmp); return rval;}/*** topo - do a topological sort of the dependency graph.*/void topo() { vertex *x = vset,*n; edge *e; vertex *outq = NULL,*tmp;#define insq(x) ((x->next = outq),(outq = x))#define deq() ((tmp = outq),(outq = outq->next),tmp) /* ** find all vertices that don't depend on any other vertices ** Since it breaks the "next" links to insert x into the queue, ** x->next is saved before insq, to resume the list traversal. */ while (x != NULL) { n = x->next; if(x->indegree == 0) { insq(x); pushname(x->key); } x = n; } /* ** for each vertex V with indegree of zero, ** for each edge E from vertex V ** subtract one from the indegree of the vertex V' ** pointed to by E. If V' now has an indegree of zero, ** add it to the set of vertices with indegree zero, and ** push its name on the output stack. */ while(outq != NULL) { x = deq(); e = x->out; while(e != NULL) { if(--(e->v->indegree) == 0) { insq(e->v); pushname(e->v->key); } e = e->next; } } /* ** print the vertex names in opposite of the order they were ** encountered. */ while(namelist != NULL) puts(popname());}/*** print_cycle --** A cycle has been detected between parent and child.** Start with the child, and look at each of its edges for** the parent.**** We know a vertex is on the path from the child to the parent** because the depth-first search sets on_the_path true for each** vertex it visits.*/voidprint_cycle(parent,child)vertex *parent, *child;{ char *s; vertex *x; edge *e; for(x = child; x != parent; ) { pushname(x->key); for(e = x->out; e != NULL; e = e->next) { /* ** stop looking for the path at the first node found ** that's on the path. Watch out for cycles already ** detected, because if you follow an edge into a cycle, ** you're stuck in an infinite loop! */ if(e->v->on_the_path && !e->v->has_a_cycle) { x = e->v; break; } } } /* ** print the name of the parent, and then names of each of the ** vertices on the path from the child to the parent. */ fprintf(stderr,"%s\n",x->key); while((s = popname()) != NULL) fprintf(stderr,"%s\n",s);}/*** depth first search for cycles in the dependency graph.** See "Introduction to Algorithms" by Udi Manber Addison-Wesley 1989*/voiddfs(v)vertex *v;{ edge *e; if(v->visited) /* If you've been here before, don't go again! */ return; v->visited++; v->on_the_path++; /* this node is on the path from the root. */ /* ** depth-first search all outgoing edges. */ for(e = v->out; e != NULL; e = e->next) { if(!e->v->visited) dfs(e->v); if(e->v->on_the_path) { fprintf(stderr,"cycle found between %s and %s\n", v->key,e->v->key); print_cycle(v,e->v); v->has_a_cycle++; } } v->on_the_path = 0;}/*** check cycles starts the recursive depth-first search from** each vertex in vset.*/voidcheck_cycles(){ vertex *v; for(v = vset; v != NULL; v = v->next) dfs(v);}/*** main program.*/int main(argc,argv)int argc;char **argv;{ if(argc > 1 && freopen(argv[1],"r",stdin) == NULL) { perror(argv[1]); exit(0); } if(argc > 2 && freopen(argv[2],"w",stdout) == NULL) { perror(argv[2]); exit(0); } readin(); check_cycles(); topo(); return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -