tsort.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. 18-Jul-84 02:10:28-EDT,3724;000000000001
  2. Received: from MIT-MC by MIT-OZ via Chaosnet; 18 Jul 84 02:10-EDT
  3. Received: from ucbernie.ARPA by UCB-VAX.ARPA (4.28/4.31)
  4. id AA08177; Tue, 17 Jul 84 22:46:34 pdt
  5. Received: by ucbernie.ARPA (4.28/4.30)
  6. id AA10610; Tue, 17 Jul 84 22:47:11 pdt
  7. Date: Tue, 17 Jul 84 22:47:11 pdt
  8. From: phr%ucbernie@Berkeley (Paul Rubin)
  9. Message-Id: <8407180547.AA10610@ucbernie.ARPA>
  10. To: rms@oz@mc
  11. Subject: I should be able to get this to run faster sometime
  12. #include <stdio.h>
  13. #define MAXLEN 1000
  14. #define HASHSIZE 10007 /* for now, MAX no. of distinct vertices */
  15. /*
  16. * tsort - topological sort. Linear time algorithm
  17. * suggested by Avi Wigderson.
  18. * --phr, 16 July 1984
  19. */
  20. struct node {
  21. char *name;
  22. int indegree; /* number of predecessors */
  23. struct nodelist *successors; /* successors in graph */
  24. struct node *next;
  25. struct node *back;
  26. };
  27. struct nodelist {
  28. struct node *id;
  29. struct nodelist *next;
  30. };
  31. typedef struct node NODE;
  32. typedef struct nodelist NLIST;
  33. NODE *graph = NULL;
  34. int nnodes = 0;
  35. main(argc, argv)
  36. int argc;
  37. char **argv;
  38. {
  39. int n = 0;
  40. NODE *lookup();
  41. register NODE *p, *q;
  42. NLIST *t;
  43. FILE *ifile = stdin;
  44. char from[MAXLEN], to[MAXLEN];
  45. if (argc > 1 && (ifile = fopen(argv[1], "r")) == NULL) {
  46. perror(argv[1]);
  47. exit(1);
  48. }
  49. while (fscanf(ifile, "%s %s", from, to) > 0) {
  50. p = lookup(from);
  51. q = lookup(to);
  52. if (p == q)
  53. continue;
  54. /* actually this scan might be taking more time than it saves */
  55. for (t = p->successors; t != NULL; t = t->next)
  56. if (t->id == q)
  57. break;
  58. if (t == NULL) { /* q not already on successor list */
  59. t = (NLIST *) malloc(sizeof (NLIST));
  60. t->id = q;
  61. t->next = p->successors;
  62. p->successors = t;
  63. ++q->indegree;
  64. }
  65. } /* each node now has a correct predecessor count and
  66. successor list. */
  67. if (nnodes == 0)
  68. exit(0);
  69. /* next, move all the root nodes to the head of the list */
  70. for (p = graph; p != NULL; p = p->next) {
  71. q = p->next;
  72. if (q == NULL)
  73. break;
  74. if (q->indegree == 0) {
  75. p->next = q->next;
  76. q->next = graph;
  77. graph = q;
  78. }
  79. }
  80. /* now turn the list into a doubly linked list */
  81. for (p = graph; p->next != NULL; p = p->next)
  82. p->next->back = p;
  83. graph->back = NULL;
  84. /* output */
  85. for (p = graph; p != NULL; nnodes--) {
  86. if (p->indegree != 0) {
  87. fprintf(stderr, "tsort: graph is circular\n");
  88. exit (1);
  89. }
  90. printf("%s\n", p->name);
  91. t = p->successors;
  92. p = p->next;
  93. for (; t != NULL; t = t->next) {
  94. q = t->id;
  95. if (--q->indegree == 0) {
  96. /* move new root to head of list. q->back->next will not
  97. be null because q had indegree > 0. */
  98. if (q == p) /* it's already at head */
  99. continue;
  100. q->back->next = q->next;
  101. if (q->next != NULL)
  102. q->next->back = q->back;
  103. q->next = p;
  104. p->back = q;
  105. p = q;
  106. p->back = NULL;
  107. }
  108. }
  109. }
  110. if (n != 0) {
  111. fprintf(stderr, "tsort: graph has cycles\n");
  112. exit (1);
  113. }
  114. exit (0);
  115. }
  116. NODE *lookup(name)
  117. char *name;
  118. {
  119. char *newstring();
  120. static NODE *hashtab[HASHSIZE];
  121. register NODE *p;
  122. register int i;
  123. for (i = hashf(name); hashtab[i] != NULL; i = (i+1)%HASHSIZE)
  124. if (strcmp(hashtab[i]->name, name) == 0)
  125. return hashtab[i];
  126. p = hashtab[i] = (NODE *) calloc(1, sizeof (NODE));
  127. p->name = newstring(name);
  128. p->next = graph;
  129. graph = p;
  130. nnodes++;
  131. return p;
  132. }
  133. static int hashf(s)
  134. register char *s;
  135. {
  136. register int r = 0;
  137. while (*s)
  138. r = (r << 1) + *s++;
  139. r &= ~0x80000000; /* make r nonnegative */
  140. return r % HASHSIZE;
  141. }
  142. char *newstring(s)
  143. char *s;
  144. {
  145. char *p = (char *) malloc(strlen(s) + 1);
  146. strcpy(p, s);
  147. return p;
  148. }