Privacy
An open-source, flexible 3D physical simulation framework
tsort.c
Go to the documentation of this file.
1 /* tsort - topological sort.
2  Copyright (C) 1998-2013 Free Software Foundation, Inc.
3 
4  This program is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program. If not, see <http://www.gnu.org/licenses/>. */
16 
17 /* Written by Mark Kettenis <kettenis@phys.uva.nl>. */
18 
19 /* The topological sort is done according to Algorithm T (Topological
20  sort) in Donald E. Knuth, The Art of Computer Programming, Volume
21  1/Fundamental Algorithms, page 262. */
22 
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <assert.h>
28 
29 /* Members of the list of successors. */
30 struct successor
31 {
32  struct item *suc;
33  struct successor *next;
34 };
35 
39 };
40 
41 static struct succ_cleanup_list *succs_to_clean = NULL;
42 
43 /* Each string is held in core as the head of a list of successors. */
44 struct item
45 {
46  unsigned long id;
47  struct item *left, *right;
48  int balance; /* -1, 0, or +1 */
49  size_t count;
50  struct item *qlink;
51  struct successor *top;
52 };
53 
55  struct item *to_clean;
57 };
58 
59 static struct item_cleanup_list *items_to_clean = NULL;
60 
61 /* The head of the sorted list. */
62 static struct item *head = NULL;
63 
64 /* The tail of the list of 'zeros', strings that have no predecessors. */
65 static struct item *zeros = NULL;
66 
67 /* Used for loop detection. */
68 static struct item *loop = NULL;
69 
70 /* The number of strings to sort. */
71 static size_t n_ids = 0;
72 
73 static struct item *root = NULL;
74 
75 static unsigned long *ids = NULL;
76 
77 
78 /* Create a new item/node for STR. */
79 static struct item *
80 new_item (unsigned long id)
81 {
82  struct item *k = malloc (sizeof *k);
83  struct item_cleanup_list *d = malloc(sizeof *d);
84 
85  d->to_clean = k;
86  d->next = items_to_clean;
87  items_to_clean = d;
88 
89  k->id = id;
90  k->left = k->right = NULL;
91  k->balance = 0;
92 
93  /* T1. Initialize (COUNT[k] <- 0 and TOP[k] <- ^). */
94  k->count = 0;
95  k->qlink = NULL;
96  k->top = NULL;
97 
98  return k;
99 }
100 
101 /* Search binary tree rooted at *ROOT for STR. Allocate a new tree if
102  *ROOT is NULL. Insert a node/item for STR if not found. Return
103  the node/item found/created for STR.
104 
105  This is done according to Algorithm A (Balanced tree search and
106  insertion) in Donald E. Knuth, The Art of Computer Programming,
107  Volume 3/Searching and Sorting, pages 455--457. */
108 
109 static struct item *
110 search_item (unsigned long id)
111 {
112  struct item *p, *q, *r, *s, *t;
113  int a;
114 
115  assert (root);
116 
117  /* Make sure the tree is not empty, since that is what the algorithm
118  below expects. */
119  if (root->right == NULL)
120  return (root->right = new_item (id));
121 
122  /* A1. Initialize. */
123  t = root;
124  s = p = root->right;
125 
126  while (1)
127  {
128  /* A2. Compare. */
129  a = id < p->id ? -1 : 1;
130  if (id == p->id)
131  return p;
132 
133  /* A3 & A4. Move left & right. */
134  if (a < 0)
135  q = p->left;
136  else
137  q = p->right;
138 
139  if (q == NULL)
140  {
141  /* A5. Insert. */
142  q = new_item (id);
143 
144  /* A3 & A4. (continued). */
145  if (a < 0)
146  p->left = q;
147  else
148  p->right = q;
149 
150  /* A6. Adjust balance factors. */
151  if (id < s->id)
152  {
153  r = p = s->left;
154  a = -1;
155  }
156  else
157  {
158  r = p = s->right;
159  a = 1;
160  }
161 
162  while (p != q)
163  {
164  if (id < p->id)
165  {
166  p->balance = -1;
167  p = p->left;
168  }
169  else
170  {
171  p->balance = 1;
172  p = p->right;
173  }
174  }
175 
176  /* A7. Balancing act. */
177  if (s->balance == 0 || s->balance == -a)
178  {
179  s->balance += a;
180  return q;
181  }
182 
183  if (r->balance == a)
184  {
185  /* A8. Single Rotation. */
186  p = r;
187  if (a < 0)
188  {
189  s->left = r->right;
190  r->right = s;
191  }
192  else
193  {
194  s->right = r->left;
195  r->left = s;
196  }
197  s->balance = r->balance = 0;
198  }
199  else
200  {
201  /* A9. Double rotation. */
202  if (a < 0)
203  {
204  p = r->right;
205  r->right = p->left;
206  p->left = r;
207  s->left = p->right;
208  p->right = s;
209  }
210  else
211  {
212  p = r->left;
213  r->left = p->right;
214  p->right = r;
215  s->right = p->left;
216  p->left = s;
217  }
218 
219  s->balance = 0;
220  r->balance = 0;
221  if (p->balance == a)
222  s->balance = -a;
223  else if (p->balance == -a)
224  r->balance = a;
225  p->balance = 0;
226  }
227 
228  /* A10. Finishing touch. */
229  if (s == t->right)
230  t->right = p;
231  else
232  t->left = p;
233 
234  return q;
235  }
236 
237  /* A3 & A4. (continued). */
238  if (q->balance)
239  {
240  t = p;
241  s = q;
242  }
243 
244  p = q;
245  }
246 
247  /* NOTREACHED */
248 }
249 
250 /* Record the fact that J precedes K. */
251 
252 static void
253 record_relation (struct item *j, struct item *k)
254 {
255  struct successor *p;
256  struct succ_cleanup_list *d;
257 
258  if (j->id != k->id)
259  {
260  k->count++;
261  p = malloc (sizeof *p);
262 
263  d = malloc(sizeof *d);
264  d->to_clean = p;
265  d->next = succs_to_clean;
266  succs_to_clean = d;
267 
268  p->suc = k;
269  p->next = j->top;
270  j->top = p;
271  }
272 }
273 
274 static int
275 count_items (struct item *unused)
276 {
277  (void)unused;
278  n_ids++;
279  return 0;
280 }
281 
282 static int
283 scan_zeros (struct item *k)
284 {
285  /* Ignore strings that have already been printed. */
286  if (k->count == 0 && k->id)
287  {
288  if (head == NULL)
289  head = k;
290  else
291  zeros->qlink = k;
292 
293  zeros = k;
294  }
295 
296  return 0;
297 }
298 
299 /* Try to detect the loop. If we have detected that K is part of a
300  loop, print the loop on standard error, remove a relation to break
301  the loop, and return true.
302 
303  The loop detection strategy is as follows: Realise that what we're
304  dealing with is essentially a directed graph. If we find an item
305  that is part of a graph that contains a cycle we traverse the graph
306  in backwards direction. In general there is no unique way to do
307  this, but that is no problem. If we encounter an item that we have
308  encountered before, we know that we've found a cycle. All we have
309  to do now is retrace our steps, printing out the items until we
310  encounter that item again. (This is not necessarily the item that
311  we started from originally.) Since the order in which the items
312  are stored in the tree is not related to the specified partial
313  ordering, we may need to walk the tree several times before the
314  loop has completely been constructed. If the loop was found, the
315  global variable LOOP will be NULL. */
316 
317 static int
318 detect_loop (struct item *k)
319 {
320  if (k->count > 0)
321  {
322  /* K does not have to be part of a cycle. It is however part of
323  a graph that contains a cycle. */
324 
325  if (loop == NULL)
326  /* Start traversing the graph at K. */
327  loop = k;
328  else
329  {
330  struct successor **p = &k->top;
331 
332  while (*p)
333  {
334  if ((*p)->suc == loop)
335  {
336  if (k->qlink)
337  {
338  /* We have found a loop. Retrace our steps. */
339  while (loop)
340  {
341  struct item *tmp = loop->qlink;
342 
343  /*
344  fprintf (stderr, "bg_tsort: %lu\n",
345  loop->id);
346  */
347  /* Until we encounter K again. */
348  if (loop == k)
349  {
350  /* Remove relation. */
351  (*p)->suc->count--;
352  *p = (*p)->next;
353  break;
354  }
355 
356  /* Tidy things up since we might have to
357  detect another loop. */
358  loop->qlink = NULL;
359  loop = tmp;
360  }
361 
362  while (loop)
363  {
364  struct item *tmp = loop->qlink;
365 
366  loop->qlink = NULL;
367  loop = tmp;
368  }
369 
370  /* Since we have found the loop, stop walking
371  the tree. */
372  return 1;
373  }
374  else
375  {
376  k->qlink = loop;
377  loop = k;
378  break;
379  }
380  }
381 
382  p = &(*p)->next;
383  }
384  }
385  }
386 
387  return 0;
388 }
389 
390 /* Recurse (sub)tree rooted at ROOT, calling ACTION for each node.
391  Stop when ACTION returns true. */
392 
393 static int
394 recurse_tree (struct item *root_node, int (*action) (struct item *))
395 {
396  if (root_node->left == NULL && root_node->right == NULL)
397  return (*action) (root_node);
398  else
399  {
400  if (root_node->left != NULL)
401  if (recurse_tree (root_node->left, action))
402  return 1;
403  if ((*action) (root_node))
404  return 1;
405  if (root_node->right != NULL)
406  if (recurse_tree (root_node->right, action))
407  return 1;
408  }
409 
410  return 0;
411 }
412 
413 /* Walk the tree specified by the head ROOT, calling ACTION for
414  each node. */
415 
416 static void
417 walk_tree (struct item *root_node, int (*action) (struct item *))
418 {
419  if (root_node->right)
420  recurse_tree (root_node->right, action);
421 }
422 
423 void add_relation(unsigned long id1, unsigned long id2) {
424  struct item *j = NULL;
425  struct item *k = NULL;
426 
427  if(root == NULL) root = new_item(0);
428 
429  /*fprintf(stderr, "add relation: %lu %lu\n", id1, id2);*/
430  j = search_item(id1);
431  k = search_item(id2);
432  record_relation(j, k);
433 }
434 
435 
436 /* Do a topological sort on FILE. Return true if successful. */
437 int tsort (void) {
438  int ok = 1;
439  int i = 0;
440 
441  struct item_cleanup_list *d;
442  struct succ_cleanup_list *dd;
443 
444  assert(root);
445 
446  /* T1. Initialize (N <- n). */
447  walk_tree (root, count_items);
448 
449  if(ids) free(ids);
450  ids = malloc(sizeof(unsigned long)*(n_ids+1));
451  while (n_ids > 0)
452  {
453  /* T4. Scan for zeros. */
454  walk_tree (root, scan_zeros);
455 
456  while (head)
457  {
458  struct successor *p = head->top;
459 
460  /* T5. Output front of queue. */
461  /*fprintf(stderr, "%lu\n", head->id);*/
462  ids[i++] = head->id;
463  head->id = 0; /* Avoid printing the same string twice. */
464  n_ids--;
465 
466  /* T6. Erase relations. */
467  while (p)
468  {
469  p->suc->count--;
470  if (p->suc->count == 0)
471  {
472  zeros->qlink = p->suc;
473  zeros = p->suc;
474  }
475 
476  p = p->next;
477  }
478 
479  /* T7. Remove from queue. */
480  head = head->qlink;
481  }
482 
483  /* T8. End of process. */
484  if (n_ids > 0)
485  {
486  /* The input contains a loop. */
487  ok = 0;
488 
489  /* Print the loop and remove a relation to break it. */
490  do
491  walk_tree (root, detect_loop);
492  while (loop);
493  }
494  }
495 
496  ids[i] = 0;
497 
498  /* Todo: clean memory (except sorted ids) */
499 
500  while(items_to_clean) {
501  free(items_to_clean->to_clean);
502  d = items_to_clean;
503  items_to_clean = items_to_clean->next;
504  free(d);
505  }
506 
507  while(succs_to_clean) {
508  free(succs_to_clean->to_clean);
509  dd = succs_to_clean;
510  succs_to_clean = succs_to_clean->next;
511  free(dd);
512  }
513 
514  root = NULL;
515  return ok;
516 }
517 
518 unsigned long* get_sorted_ids(void) {
519  return ids;
520 }
struct successor * top
Definition: tsort.c:51
struct item * right
Definition: tsort.c:47
static unsigned long * ids
Definition: tsort.c:75
struct item * suc
Definition: tsort.c:32
Definition: tsort.c:44
static int scan_zeros(struct item *k)
Definition: tsort.c:283
struct item * qlink
Definition: tsort.c:50
static struct item * root
Definition: tsort.c:73
u_int8_t r
Definition: CameraSensor.h:41
static int recurse_tree(struct item *root_node, int(*action)(struct item *))
Definition: tsort.c:394
static void walk_tree(struct item *root_node, int(*action)(struct item *))
Definition: tsort.c:417
struct item_cleanup_list * next
Definition: tsort.c:56
static int count_items(struct item *unused)
Definition: tsort.c:275
u_int8_t a
Definition: CameraSensor.h:44
struct successor * to_clean
Definition: tsort.c:37
static struct item * loop
Definition: tsort.c:68
struct item * left
Definition: tsort.c:47
static struct item_cleanup_list * items_to_clean
Definition: tsort.c:59
static struct succ_cleanup_list * succs_to_clean
Definition: tsort.c:41
struct item * to_clean
Definition: tsort.c:55
struct succ_cleanup_list * next
Definition: tsort.c:38
static size_t n_ids
Definition: tsort.c:71
int balance
Definition: tsort.c:48
struct successor * next
Definition: tsort.c:33
void add_relation(unsigned long id1, unsigned long id2)
Definition: tsort.c:423
static void record_relation(struct item *j, struct item *k)
Definition: tsort.c:253
int tsort(void)
Definition: tsort.c:437
static int detect_loop(struct item *k)
Definition: tsort.c:318
unsigned long id
Definition: tsort.c:46
size_t count
Definition: tsort.c:49
unsigned long * get_sorted_ids(void)
Definition: tsort.c:518
static struct item * search_item(unsigned long id)
Definition: tsort.c:110
static struct item * new_item(unsigned long id)
Definition: tsort.c:80
static struct item * head
Definition: tsort.c:62
static struct item * zeros
Definition: tsort.c:65