home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume28 / librb / part01 < prev    next >
Encoding:
Text File  |  1992-02-22  |  29.2 KB  |  1,134 lines

  1. Newsgroups: comp.sources.misc
  2. From: jsp@Princeton.EDU (James Plank)
  3. Subject:  v28i062:  librb - red-black tree data structure routines, Part01/01
  4. Message-ID: <1992Feb24.025345.8578@sparky.imd.sterling.com>
  5. X-Md4-Signature: 12b8683edf1c299d2a26b27305f4467d
  6. Date: Mon, 24 Feb 1992 02:53:45 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: jsp@Princeton.EDU (James Plank)
  10. Posting-number: Volume 28, Issue 62
  11. Archive-name: librb/part01
  12. Environment: UNIX
  13.  
  14. I've had this code hanging around for a while and a bunch of people at
  15. Princeton have found it useful, so I figured I'd post it.  It's a library
  16. of routines for doing red-black trees, which is basically a sorted data
  17. structure in which all the operations are log(n) time.  I've used them
  18. to replace hash tables because with rb-tree's, I don't need to do any
  19. hash-table initialization, they can be of arbitrary size, they have a 
  20. better worst-case behavior, and they're sorted.  
  21.  
  22. This code has been around since June and has been beaten on by many
  23. people, so it should be very stable.  Check out the README for all 
  24. the details.  If you have any questions or comments about this, please 
  25. let me know.
  26.  
  27. Take it Easy,
  28.  
  29. Jim Plank
  30. jsp@princeton.edu or
  31. plank@cs.utk.edu
  32. -------------------
  33. #! /bin/sh
  34. # This is a shell archive.  Remove anything before this line, then feed it
  35. # into a shell via "sh file" or similar.  To overwrite existing files,
  36. # type "sh file -c".
  37. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  38. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  39. # Contents:  README list.c list.h main.c makefile rb.c rb.h
  40. # Wrapped by kent@sparky on Sun Feb 23 20:39:24 1992
  41. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  42. echo If this archive is complete, you will see the following message:
  43. echo '          "shar: End of archive 1 (of 1)."'
  44. if test -f 'README' -a "${1}" != "-c" ; then 
  45.   echo shar: Will not clobber existing file \"'README'\"
  46. else
  47.   echo shar: Extracting \"'README'\" \(4998 characters\)
  48.   sed "s/^X//" >'README' <<'END_OF_FILE'
  49. X$Revision: 1.1 $
  50. X
  51. XRb.c, Rb.h, List.h, and list.c are files for doing red-black trees and 
  52. Xdoubly linked lists, respectively.
  53. X
  54. XRb.h, Rb.c:
  55. X
  56. XRb.h contains the typedef for red-black tree structures.  Basically, 
  57. Xred-black trees are balanced trees whose external nodes are sorted
  58. Xby a key, and connected in a linked list.  The following is how
  59. Xyou use rb.c and rb.h:
  60. X
  61. XInclude rb.h in your source.
  62. X
  63. XMake_rb() returns the head of a red-black tree.  It serves two functions:
  64. XIts p.root pointer points to the root of the red-black tree.  Its 
  65. Xc.list.flink and c.list.blink pointers point to the first and last 
  66. Xexternal nodes of the tree.  When the tree is empty, all these pointers
  67. Xpoint to itself.
  68. X
  69. XThe external nodes can be traversed in sorted order with their
  70. Xc.list.flink and c.list.blink pointers.  The macros rb_first, rb_last,
  71. Xrb_next, rb_prev, and rb_traverse can be used to traverse external node lists.
  72. X
  73. XExternal nodes hold two pieces of information: the key and the value
  74. X(in k.key and v.val, respectively).   The key can be a character 
  75. Xstring, an integer, or a general pointer.  Val is typed as a character
  76. Xpointer, but can be any pointer.  If the key is a character string, 
  77. Xthen one can insert it, and a value into a tree with rb_insert().  If
  78. Xit is an integer, then rb_inserti() should be used.  If it is a general 
  79. Xpointer, then rb_insertg() must be used, with a comparison function 
  80. Xpassed as the fourth argument.  This function takes two keys as arguments,
  81. Xand returns a negative value, positive value, or 0, depending on whether
  82. Xthe first key is less than, greater than or equal to the second.  Thus,
  83. Xone could use rb_insertg(t, s, v, strcmp) to insert the value v with 
  84. Xa character string s into the tree t.
  85. X
  86. XRb_find_key(t, k) returns the external node in t whose value is equal
  87. Xk or whose value is the smallest value greater than k.  (Here, k is
  88. Xa string).  If there is no value greater than or equal to k, then 
  89. Xt is returned.  Rb_find_ikey(t,k) works when k is an integer, and 
  90. XRb_find_gkey(t,k,cmp) works for general pointers.
  91. X
  92. XRb_find_key_n(t, k, n) is the same as rb_find_key, except that it
  93. Xreturns whether or not k was found in n (n is an int *).  Rb_find_ikey_n
  94. Xand Rb_find_gkey_n are the analogous routines for integer and general
  95. Xkeys.
  96. X
  97. XRb_insert_b(e, k, v) makes a new external node with key k and val v, and 
  98. Xinserts it before the external node e.  If e is the head of a tree, 
  99. Xthen the new node is inserted at the end of the external node list.
  100. XIf this insertion violates sorted order, no error is flagged.  It is 
  101. Xassumed that the user knows what he/she is doing.  Rb_insert_a(e,k,v)
  102. Xinserts the new node after e (if e = t, it inserts the new node at the
  103. Xbeginning of the list).
  104. X
  105. XRb_insert() is therefore really a combination of Rb_find_key() and
  106. XRb_insert_b().
  107. X
  108. XRb_delete_node(e) deletes the external node e from a tree (and thus from 
  109. Xthe linked list of external nodes).  The node is free'd as well, so
  110. Xdon't retain pointers to it.
  111. X
  112. XRed-black trees are spiffy because find_key, insert, and delete are all
  113. Xdone in log(n) time.  Thus, they can be freely used instead of hash-tables,
  114. Xwith the benifit of having the elements in sorted order at all times, and
  115. Xwith the guarantee of operations being in log(n) time.
  116. X
  117. XOther routines:
  118. X
  119. XRb_print_tree() will grossly print out a red-black tree with string keys.
  120. XRb_iprint_tree() will do the same with trees with integer keys.
  121. XRb_nblack(e) will report the number of black nodes on the path from external
  122. X  node e to the root.  The path length is less than twice this value.
  123. XRb_plength(e) reports the length of the path from e to the root.
  124. X
  125. X
  126. XList.c and list.h
  127. X
  128. XThese are routines for generic doubly linked lists.  Doubly linked lists
  129. Xare any structs whose first two fields are flink and blink pointers.
  130. XMk_list(t) returns an empty list with the type t.  The empty list is 
  131. Xa struct whose flink and blink point to itself.  Insert() and delete_item()
  132. Xinsert and delete nodes from a list -- unlike the rb routines, no allocation
  133. Xis done here.  In insert(), the node to be inserted is assumed to be allocated,
  134. Xand in delete_item(), the deleted node is not free'd.
  135. X
  136. XGet_node() allocates a node from a node list.  The head element in the linked
  137. Xlist has info about how big of a node to allocate.  Free_node() deallocates
  138. Xa node.  In actuality, free_node doesn't call free, but chains the node onto
  139. Xa queue of nodes.  That way, get_node first returns nodes from this queue, 
  140. Xand malloc need not be called.  This is quite a possible memory leak.  To
  141. Xbe safe, you can malloc and free your own nodes, instead of calling get_node()
  142. Xand free_node().
  143. X
  144. XList.c and list.h are kind of gross, and should be generally avoided because
  145. Xof allocation problems.  Try dlist.c & dlist.h for doubly linked lists which
  146. Xare more like the red-black tree structs.
  147. X
  148. XIf you have any questions or comments about this, please let me know.
  149. X
  150. XTake it Easy,
  151. X
  152. XJim Plank
  153. Xjsp@princeton.edu or
  154. Xplank@cs.utk.edu
  155. X
  156. X35 Olden St
  157. XPrinceton University
  158. XPrinceton, NJ 80544-2087
  159. END_OF_FILE
  160.   if test 4998 -ne `wc -c <'README'`; then
  161.     echo shar: \"'README'\" unpacked with wrong size!
  162.   fi
  163.   # end of 'README'
  164. fi
  165. if test -f 'list.c' -a "${1}" != "-c" ; then 
  166.   echo shar: Will not clobber existing file \"'list.c'\"
  167. else
  168.   echo shar: Extracting \"'list.c'\" \(2214 characters\)
  169.   sed "s/^X//" >'list.c' <<'END_OF_FILE'
  170. X/* 
  171. X * $Source: /n/fs/vd/jsp/src/rb/RCS/list.c,v $
  172. X * $Revision: 1.1 $
  173. X * $Date: 92/02/12 15:43:24 $
  174. X * $Author: jsp $
  175. X */
  176. X
  177. X#include <stdio.h>    /* Basic includes and definitions */
  178. X#include "list.h"
  179. X
  180. X#define boolean int
  181. X#define TRUE 1
  182. X#define FALSE 0
  183. X
  184. X
  185. X/*---------------------------------------------------------------------*
  186. X * PROCEDURES FOR MANIPULATING DOUBLY LINKED LISTS 
  187. X * Each list contains a sentinal node, so that     
  188. X * the first item in list l is l->flink.  If l is  
  189. X * empty, then l->flink = l->blink = l.            
  190. X * The sentinal contains extra information so that these operations
  191. X * can work on lists of any size and type.
  192. X * Memory management is done explicitly to avoid the slowness of
  193. X * malloc and free.  The node size and the free list are contained
  194. X * in the sentinal node.
  195. X *---------------------------------------------------------------------*/
  196. X
  197. Xtypedef struct int_list {  /* Information held in the sentinal node */
  198. X  struct int_list *flink;
  199. X  struct int_list *blink;
  200. X  int size;
  201. X  List free_list;
  202. X} *Int_list;
  203. X
  204. Xinsert(item, list)    /* Inserts to the end of a list */
  205. XList item;
  206. XList list;
  207. X{
  208. X  List last_node;
  209. X
  210. X  last_node = list->blink;
  211. X
  212. X  list->blink = item;
  213. X  last_node->flink = item;
  214. X  item->blink = last_node;
  215. X  item->flink = list;
  216. X}
  217. X
  218. Xdelete_item(item)        /* Deletes an arbitrary iterm */
  219. XList item;
  220. X{
  221. X  item->flink->blink = item->blink;
  222. X  item->blink->flink = item->flink;
  223. X}
  224. X
  225. XList make_list(size)    /* Creates a new list */
  226. Xint size;
  227. X{
  228. X  Int_list l;
  229. X
  230. X  l = (Int_list) malloc(sizeof(struct int_list));
  231. X  l->flink = l;
  232. X  l->blink = l;
  233. X  l->size = size;
  234. X  l->free_list = (List) malloc (sizeof(struct list));
  235. X  l->free_list->flink = l->free_list;
  236. X  return (List) l;
  237. X}
  238. X  
  239. XList get_node(list)   /* Allocates a node to be inserted into the list */
  240. XList list;
  241. X{
  242. X  Int_list l;
  243. X  List to_return;
  244. X
  245. X  l = (Int_list) list;
  246. X  if (l->free_list->flink == l->free_list) {
  247. X    return (List) malloc(l->size);
  248. X  } else {
  249. X    to_return = l->free_list;
  250. X    l->free_list = to_return->flink;
  251. X    return to_return;
  252. X  }
  253. X}
  254. X
  255. Xfree_node(node, list)    /* Deallocates a node from the list */
  256. XList node;
  257. XList list;
  258. X{
  259. X  Int_list l;
  260. X  
  261. X  l = (Int_list) list;
  262. X  node->flink = l->free_list;
  263. X  l->free_list = node;
  264. X}
  265. END_OF_FILE
  266.   if test 2214 -ne `wc -c <'list.c'`; then
  267.     echo shar: \"'list.c'\" unpacked with wrong size!
  268.   fi
  269.   # end of 'list.c'
  270. fi
  271. if test -f 'list.h' -a "${1}" != "-c" ; then 
  272.   echo shar: Will not clobber existing file \"'list.h'\"
  273. else
  274.   echo shar: Extracting \"'list.h'\" \(1025 characters\)
  275.   sed "s/^X//" >'list.h' <<'END_OF_FILE'
  276. X/* 
  277. X * $Source: /n/fs/vd/jsp/src/rb/RCS/list.h,v $
  278. X * $Revision: 1.1 $
  279. X * $Date: 92/02/12 15:43:13 $
  280. X * $Author: jsp $
  281. X */
  282. X
  283. X/* This is the header file for the list manipulation routines in list.c.
  284. X * Any struct can be turned into a list as long as its first two fields are
  285. X * flink and blink. */
  286. X
  287. Xtypedef struct list {
  288. X  struct list *flink;
  289. X  struct list *blink;
  290. X} *List;
  291. X
  292. X/* Nil, first, next, and prev are macro expansions for list traversal 
  293. X * primitives. */
  294. X
  295. X#define nil(l) (l)
  296. X#define first(l) (l->flink)
  297. X#define last(l) (l->blink)
  298. X#define next(n) (n->flink)
  299. X#define prev(n) (n->blink)
  300. X
  301. X#define mklist(t) ((t *) make_list (sizeof(t)))
  302. X
  303. X/* These are the routines for manipluating lists */
  304. X
  305. X/* void insert(node list);     Inserts a node to the end of a list */
  306. X/* void delete_item(node);     Deletes an arbitrary node */
  307. X/* List make_list(node_size);  Creates a new list */
  308. X/* List get_node(list);        Allocates a node to be inserted into the list */
  309. X/* void free_node(node, list); Deallocates a node from the list */
  310. X
  311. END_OF_FILE
  312.   if test 1025 -ne `wc -c <'list.h'`; then
  313.     echo shar: \"'list.h'\" unpacked with wrong size!
  314.   fi
  315.   # end of 'list.h'
  316. fi
  317. if test -f 'main.c' -a "${1}" != "-c" ; then 
  318.   echo shar: Will not clobber existing file \"'main.c'\"
  319. else
  320.   echo shar: Extracting \"'main.c'\" \(1810 characters\)
  321.   sed "s/^X//" >'main.c' <<'END_OF_FILE'
  322. X#include "rb.h"
  323. X#include <stdio.h>
  324. X
  325. X/* an example -- this allocates a red-black tree for integers.  For a 
  326. X * user-specified number of iterations, it does the following:
  327. X
  328. X * delete a random element in the tree.
  329. X * make two new random elements, and insert them into the tree
  330. X * At the end, it prints the sorted list of elements, and then prints
  331. X * stats of the number of black nodes in any path in the tree, and 
  332. X * the minimum and maximum path lengths.
  333. X  
  334. X * Rb_find_ikey and rb_inserti could have been used, but instead
  335. X * rb_find_gkey and rb_insertg were used to show how they work.
  336. X  
  337. X */
  338. X
  339. Xint icomp(i, j)
  340. Xint i, j;
  341. X{
  342. X  if (i == j) return 0;
  343. X  if (i > j) return -1; else return 1;
  344. X}
  345. X
  346. Xmain(argc, argv)
  347. Xint argc;
  348. Xchar **argv;
  349. X{
  350. X  int i, j, tb, nb, mxp, mnp, p;
  351. X  int iterations;
  352. X  Rb_node argt, t;
  353. X  int *a;
  354. X
  355. X  if (argc != 2) {
  356. X    fprintf(stderr, "usage: main #iterations\n");
  357. X    exit(1);
  358. X  }
  359. X  argt = make_rb();
  360. X  srandom(time(0));
  361. X  iterations = atoi(argv[1]);
  362. X  a = (int *) malloc (iterations*sizeof(int));
  363. X
  364. X  for (i = 0; i < atoi(argv[1]); i++) {
  365. X    if (i > 0) {
  366. X      j = random()%i;
  367. X      
  368. X      rb_delete_node(rb_find_gkey(argt, a[j], icomp));
  369. X      a[j] = random() % 1000;
  370. X      rb_insertg(argt, a[j], 0, icomp);
  371. X    }
  372. X    a[i] = random() % 1000;
  373. X    rb_insertg(argt, a[i], 0, icomp);
  374. X  }
  375. X  tb = 0;
  376. X  mxp = 0;
  377. X  mnp = 0;
  378. X  for (t = rb_first(argt); t != nil(argt); t = rb_next(t)) {
  379. X    printf("%d ", t->k.ikey);
  380. X    nb = rb_nblack(t);
  381. X    p = rb_plength(t);
  382. X    if (tb == 0) {
  383. X      tb = nb;
  384. X    } else if (tb != nb) {
  385. X      printf("Conflict: tb=%d, nb=%d\n", tb, nb);
  386. X      exit(1);
  387. X    }
  388. X    mxp = (mxp == 0 || mxp < p) ? p : mxp;
  389. X    mnp = (mnp == 0 || mxp > p) ? p : mnp;
  390. X  }
  391. X  printf("\n");  
  392. X
  393. X  printf("Nblack = %d\n", tb);
  394. X  printf("Max    = %d\n", mxp);
  395. X  printf("Min    = %d\n", mnp);
  396. X}
  397. END_OF_FILE
  398.   if test 1810 -ne `wc -c <'main.c'`; then
  399.     echo shar: \"'main.c'\" unpacked with wrong size!
  400.   fi
  401.   # end of 'main.c'
  402. fi
  403. if test -f 'makefile' -a "${1}" != "-c" ; then 
  404.   echo shar: Will not clobber existing file \"'makefile'\"
  405. else
  406.   echo shar: Extracting \"'makefile'\" \(431 characters\)
  407.   sed "s/^X//" >'makefile' <<'END_OF_FILE'
  408. XCC = cc
  409. XCFLAGS    =    -g
  410. X
  411. XOBJS = rb.o list.o
  412. X
  413. XMOBJS = main.o librb.a
  414. X
  415. Xall: librb.a main
  416. X
  417. Xlibrb.a: $(OBJS)
  418. X    ar ru librb.a $(OBJS)
  419. X    ranlib librb.a
  420. X    rm *.o
  421. X
  422. Xdepend: 
  423. X    makedep .
  424. X
  425. Xmain: $(MOBJS)
  426. X    $(CC) $(CFLAGS) -o main $(MOBJS)
  427. X
  428. X.c.o:
  429. X    $(CC) -c $(CFLAGS) $*.c
  430. X
  431. Xclean:
  432. X    rm *.o librb.a main
  433. X
  434. X# +mkdep+ 
  435. Xlist.o: \
  436. X          ./list.h \
  437. X          list.c
  438. X
  439. Xmain.o: \
  440. X          ./rb.h \
  441. X          main.c
  442. X
  443. Xrb.o: \
  444. X          ./rb.h \
  445. X          rb.c
  446. X
  447. END_OF_FILE
  448.   if test 431 -ne `wc -c <'makefile'`; then
  449.     echo shar: \"'makefile'\" unpacked with wrong size!
  450.   fi
  451.   # end of 'makefile'
  452. fi
  453. if test -f 'rb.c' -a "${1}" != "-c" ; then 
  454.   echo shar: Will not clobber existing file \"'rb.c'\"
  455. else
  456.   echo shar: Extracting \"'rb.c'\" \(11987 characters\)
  457.   sed "s/^X//" >'rb.c' <<'END_OF_FILE'
  458. X#include "rb.h"
  459. X#include <stdio.h>
  460. X
  461. X#define isred(n) (n->s.red)
  462. X#define isblack(n) (!isred(n))
  463. X#define isleft(n) (n->s.left)
  464. X#define isright(n) (!isleft(n))
  465. X#define isint(n) (n->s.internal)
  466. X#define isext(n) (!isint(n))
  467. X#define ishead(n) (n->s.head)
  468. X#define isroot(n) (n->s.root)
  469. X#define setred(n) n->s.red = 1
  470. X#define setblack(n) n->s.red = 0
  471. X#define setleft(n) n->s.left = 1
  472. X#define setright(n) n->s.left = 0
  473. X#define sethead(n) n->s.head = 1
  474. X#define setroot(n) n->s.root = 1
  475. X#define setint(n) n->s.internal = 1
  476. X#define setext(n) n->s.internal = 0
  477. X#define setnormal(n) { n->s.root = 0; n ->s.head = 0; }
  478. X#define sibling(n) ((isleft(n)) ? n->p.parent->c.child.right \
  479. X                                : n->p.parent->c.child.left)
  480. X
  481. X#define mk_new_ext(new, kkkey, vvval) {\
  482. X  new = (Rb_node) malloc(sizeof(struct rb_node));\
  483. X  new->v.val = vvval;\
  484. X  new->k.key = kkkey;\
  485. X  setext(new);\
  486. X  setblack(new);\
  487. X  setnormal(new);\
  488. X}
  489. X
  490. Xmk_new_int(l, r, p, il)
  491. XRb_node l, r, p;
  492. Xint il;
  493. X{
  494. X  Rb_node new;
  495. X
  496. X  new = (Rb_node) malloc(sizeof(struct rb_node));
  497. X  setint(new);
  498. X  setred(new);
  499. X  setnormal(new);
  500. X  new->c.child.left = l;
  501. X  new->c.child.right = r;
  502. X  new->p.parent = p;
  503. X  new->k.lext = l;
  504. X  new->v.rext = r;
  505. X  l->p.parent = new;
  506. X  r->p.parent = new;
  507. X  setleft(l);
  508. X  setright(r);
  509. X  if (ishead(p)) {
  510. X    p->p.root = new;
  511. X    setroot(new);
  512. X  } else if (il) {
  513. X    setleft(new);
  514. X    p->c.child.left = new;
  515. X  } else {
  516. X    setright(new);
  517. X    p->c.child.right = new;
  518. X  }
  519. X  recolor(new);
  520. X}  
  521. X  
  522. X   
  523. XRb_node lprev(n)
  524. XRb_node n;
  525. X{
  526. X  if (ishead(n)) return n;
  527. X  while (!isroot(n)) {
  528. X    if (isright(n)) return n->p.parent;
  529. X    n = n->p.parent;
  530. X  }
  531. X  return n->p.parent;
  532. X}
  533. X
  534. XRb_node rprev(n)
  535. XRb_node n;
  536. X{
  537. X  if (ishead(n)) return n;
  538. X  while (!isroot(n)) {
  539. X    if (isleft(n)) return n->p.parent;
  540. X    n = n->p.parent;
  541. X  }
  542. X  return n->p.parent;
  543. X}
  544. X
  545. XRb_node make_rb()
  546. X{
  547. X  Rb_node head;
  548. X
  549. X  head = (Rb_node) malloc (sizeof(struct rb_node));
  550. X  head->c.list.flink = head;
  551. X  head->c.list.blink = head;
  552. X  head->p.root = head;
  553. X  head->k.key = "";
  554. X  sethead(head);
  555. X  return head;
  556. X}
  557. X
  558. XRb_node rb_find_key_n(n, key, fnd)
  559. XRb_node n;
  560. Xchar *key;
  561. Xint *fnd;
  562. X{
  563. X  int cmp;
  564. X
  565. X  *fnd = 0;
  566. X  if (!ishead(n)) {
  567. X    fprintf(stderr, "rb_find_key_n called on non-head 0x%x\n", n);
  568. X    exit(1);
  569. X  }
  570. X  if (n->p.root == n) return n;
  571. X  cmp = strcmp(key, n->c.list.blink->k.key);
  572. X  if (cmp == 0) {
  573. X    *fnd = 1;
  574. X    return n->c.list.blink; 
  575. X  }
  576. X  if (cmp > 0) return n; 
  577. X  else n = n->p.root;
  578. X  while (1) {
  579. X    if (isext(n)) return n;
  580. X    cmp = strcmp(key, n->k.lext->k.key);
  581. X    if (cmp == 0) {
  582. X      *fnd = 1;
  583. X      return n->k.lext;
  584. X    }
  585. X    if (cmp < 0) n = n->c.child.left ; else n = n->c.child.right;
  586. X  }
  587. X}
  588. X
  589. XRb_node rb_find_key(n, key)
  590. XRb_node n;
  591. Xchar *key;
  592. X{
  593. X  int fnd;
  594. X  return rb_find_key_n(n, key, &fnd);
  595. X}
  596. X
  597. XRb_node rb_find_ikey_n(n, ikey, fnd)
  598. XRb_node n;
  599. Xint ikey;
  600. Xint *fnd;
  601. X{
  602. X  *fnd = 0;
  603. X  if (!ishead(n)) {
  604. X    fprintf(stderr, "rb_find_ikey_n called on non-head 0x%x\n", n);
  605. X    exit(1);
  606. X  }
  607. X  if (n->p.root == n) return n;
  608. X  if (ikey == n->c.list.blink->k.ikey) {
  609. X    *fnd = 1;
  610. X    return n->c.list.blink; 
  611. X  }
  612. X  if (ikey > n->c.list.blink->k.ikey) return n; 
  613. X  else n = n->p.root;
  614. X  while (1) {
  615. X    if (isext(n)) return n;
  616. X    if (ikey == n->k.lext->k.ikey) {
  617. X      *fnd = 1;
  618. X      return n->k.lext;
  619. X    }
  620. X    n = (ikey < n->k.lext->k.ikey) ? n->c.child.left : n->c.child.right;
  621. X  }
  622. X}
  623. X
  624. XRb_node rb_find_ikey(n, ikey)
  625. XRb_node n;
  626. Xint ikey;
  627. X{
  628. X  int fnd;
  629. X  return rb_find_ikey_n(n, ikey, &fnd);
  630. X}
  631. X
  632. XRb_node rb_find_gkey_n(n, key, fxn, fnd)
  633. XRb_node n;
  634. Xchar *key;
  635. Xint (*fxn)();
  636. Xint *fnd;
  637. X{
  638. X  int cmp;
  639. X
  640. X  *fnd = 0;
  641. X  if (!ishead(n)) {
  642. X    fprintf(stderr, "rb_find_key_n called on non-head 0x%x\n", n);
  643. X    exit(1);
  644. X  }
  645. X  if (n->p.root == n) return n;
  646. X  cmp = (*fxn)(key, n->c.list.blink->k.key);
  647. X  if (cmp == 0) {
  648. X    *fnd = 1;
  649. X    return n->c.list.blink; 
  650. X  }
  651. X  if (cmp > 0) return n; 
  652. X  else n = n->p.root;
  653. X  while (1) {
  654. X    if (isext(n)) return n;
  655. X    cmp = (*fxn)(key, n->k.lext->k.key);
  656. X    if (cmp == 0) {
  657. X      *fnd = 1;
  658. X      return n->k.lext;
  659. X    }
  660. X    if (cmp < 0) n = n->c.child.left ; else n = n->c.child.right;
  661. X  }
  662. X}
  663. X
  664. XRb_node rb_find_gkey(n, key, fxn)
  665. XRb_node n;
  666. Xchar *key;
  667. Xint (*fxn)();
  668. X{
  669. X  int *fnd;
  670. X  return rb_find_gkey_n(n, key, fxn, &fnd);
  671. X}
  672. XRb_node rb_insert_b(n, key, val)
  673. XRb_node n;
  674. Xchar *key;
  675. Xchar *val;
  676. X{
  677. X  Rb_node newleft, newright, newnode, list, p;
  678. X
  679. X  if (ishead(n)) {
  680. X    if (n->p.root == n) {         /* Tree is empty */
  681. X      mk_new_ext(newnode, key, val);
  682. X      insert(newnode, n);
  683. X      n->p.root = newnode;
  684. X      newnode->p.parent = n;
  685. X      setroot(newnode);
  686. X      return newnode;
  687. X    } else {
  688. X      mk_new_ext(newright, key, val);
  689. X      insert(newright, n);
  690. X      newleft = newright->c.list.blink;
  691. X      setnormal(newleft);
  692. X      mk_new_int(newleft, newright, newleft->p.parent, isleft(newleft));
  693. X      p = rprev(newright);
  694. X      if (!ishead(p)) p->k.lext = newright;
  695. X      return newright;
  696. X    }
  697. X  } else {
  698. X    mk_new_ext(newleft, key, val);
  699. X    insert(newleft, n);
  700. X    setnormal(n);
  701. X    mk_new_int(newleft, n, n->p.parent, isleft(n));
  702. X    p = lprev(newleft);
  703. X    if (!ishead(p)) p->v.rext = newleft;
  704. X    return newleft;    
  705. X  }
  706. X}
  707. X
  708. Xrecolor(n)
  709. XRb_node n;
  710. X{  
  711. X  Rb_node p, gp, s;
  712. X  int done = 0;
  713. X
  714. X  while(!done) {
  715. X    if (isroot(n)) {
  716. X      setblack(n);
  717. X      return;
  718. X    }
  719. X
  720. X    p = n->p.parent;
  721. X
  722. X    if (isblack(p)) return;
  723. X    
  724. X    if (isroot(p)) {
  725. X      setblack(p);
  726. X      return;
  727. X    }
  728. X
  729. X    gp = p->p.parent;
  730. X    s = sibling(p);
  731. X    if (isred(s)) {
  732. X      setblack(p);
  733. X      setred(gp);
  734. X      setblack(s);
  735. X      n = gp;
  736. X    } else {
  737. X      done = 1;
  738. X    }
  739. X  }
  740. X  /* p's sibling is black, p is red, gp is black */
  741. X  
  742. X  if ((isleft(n) == 0) == (isleft(p) == 0)) {
  743. X    single_rotate(gp, isleft(n));
  744. X    setblack(p);
  745. X    setred(gp);
  746. X  } else {
  747. X    single_rotate(p, isleft(n));
  748. X    single_rotate(gp, isleft(n));
  749. X    setblack(n);
  750. X    setred(gp);
  751. X  }
  752. X}
  753. X
  754. Xsingle_rotate(y, l)
  755. XRb_node y;
  756. Xint l;
  757. X{
  758. X  int rl, ir;
  759. X  Rb_node x, yp;
  760. X  char *tmp;
  761. X
  762. X  ir = isroot(y);
  763. X  yp = y->p.parent;
  764. X  if (!ir) {
  765. X    rl = isleft(y);
  766. X  }
  767. X  
  768. X  if (l) {
  769. X    x = y->c.child.left;
  770. X    y->c.child.left = x->c.child.right;
  771. X    setleft(y->c.child.left);
  772. X    y->c.child.left->p.parent = y;
  773. X    x->c.child.right = y;
  774. X    setright(y);  
  775. X  } else {
  776. X    x = y->c.child.right;
  777. X    y->c.child.right = x->c.child.left;
  778. X    setright(y->c.child.right);
  779. X    y->c.child.right->p.parent = y;
  780. X    x->c.child.left = y;
  781. X    setleft(y);  
  782. X  }
  783. X
  784. X  x->p.parent = yp;
  785. X  y->p.parent = x;
  786. X  if (ir) {
  787. X    yp->p.root = x;
  788. X    setnormal(y);
  789. X    setroot(x);
  790. X  } else {
  791. X    if (rl) {
  792. X      yp->c.child.left = x;
  793. X      setleft(x);
  794. X    } else {
  795. X      yp->c.child.right = x;
  796. X      setright(x);
  797. X    }
  798. X  }
  799. X}
  800. X    
  801. Xrb_delete_node(n)
  802. XRb_node n;
  803. X{
  804. X  Rb_node s, p, gp;
  805. X  char ir;
  806. X
  807. X  if (isint(n)) {
  808. X    fprintf(stderr, "Cannot delete an internal node: 0x%x\n", n);
  809. X    exit(1);
  810. X  }
  811. X  if (ishead(n)) {
  812. X    fprintf(stderr, "Cannot delete the head of an rb_tree: 0x%x\n", n);
  813. X    exit(1);
  814. X  }
  815. X  delete_item(n); /* Delete it from the list */
  816. X  p = n->p.parent;  /* The only node */
  817. X  if (isroot(n)) {
  818. X    p->p.root = p;
  819. X    free(n);
  820. X    return;
  821. X  } 
  822. X  s = sibling(n);    /* The only node after deletion */
  823. X  if (isroot(p)) {
  824. X    s->p.parent = p->p.parent;
  825. X    s->p.parent->p.root = s;
  826. X    setroot(s);
  827. X    free(p);
  828. X    free(n);
  829. X    return;
  830. X  }
  831. X  gp = p->p.parent;  /* Set parent to sibling */
  832. X  s->p.parent = gp;
  833. X  if (isleft(p)) {
  834. X    gp->c.child.left = s;
  835. X    setleft(s);
  836. X  } else {
  837. X    gp->c.child.right = s;
  838. X    setright(s);
  839. X  }
  840. X  ir = isred(p);
  841. X  free(p);
  842. X  free(n);
  843. X  
  844. X  if (isext(s)) {      /* Update proper rext and lext values */
  845. X    p = lprev(s); 
  846. X    if (!ishead(p)) p->v.rext = s;
  847. X    p = rprev(s);
  848. X    if (!ishead(p)) p->k.lext = s;
  849. X  } else if (isblack(s)) {
  850. X    fprintf(stderr, "DELETION PROB -- sib is black, internal\n");
  851. X    exit(1);
  852. X  } else {
  853. X    p = lprev(s);
  854. X    if (!ishead(p)) p->v.rext = s->c.child.left;
  855. X    p = rprev(s);
  856. X    if (!ishead(p)) p->k.lext = s->c.child.right;
  857. X    setblack(s);
  858. X    return;
  859. X  }
  860. X
  861. X  if (ir) return;
  862. X
  863. X  /* Recolor */
  864. X  
  865. X  n = s;
  866. X  p = n->p.parent;
  867. X  s = sibling(n);
  868. X  while(isblack(p) && isblack(s) && isint(s) && 
  869. X        isblack(s->c.child.left) && isblack(s->c.child.right)) {
  870. X    setred(s);
  871. X    n = p;
  872. X    if (isroot(n)) return;
  873. X    p = n->p.parent;
  874. X    s = sibling(n);
  875. X  }
  876. X  
  877. X  if (isblack(p) && isred(s)) {  /* Rotation 2.3b */
  878. X    single_rotate(p, isright(n));
  879. X    setred(p);
  880. X    setblack(s);
  881. X    s = sibling(n);
  882. X  }
  883. X    
  884. X  { Rb_node x, z; char il;
  885. X    
  886. X    if (isext(s)) {
  887. X      fprintf(stderr, "DELETION ERROR: sibling not internal\n");
  888. X      exit(1);
  889. X    }
  890. X
  891. X    il = isleft(n);
  892. X    x = il ? s->c.child.left : s->c.child.right ;
  893. X    z = sibling(x);
  894. X
  895. X    if (isred(z)) {  /* Rotation 2.3f */
  896. X      single_rotate(p, !il);
  897. X      setblack(z);
  898. X      if (isred(p)) setred(s); else setblack(s);
  899. X      setblack(p);
  900. X    } else if (isblack(x)) {   /* Recoloring only (2.3c) */
  901. X      if (isred(s) || isblack(p)) {
  902. X        fprintf(stderr, "DELETION ERROR: 2.3c not quite right\n");
  903. X        exit(1);
  904. X      }
  905. X      setblack(p);
  906. X      setred(s);
  907. X      return;
  908. X    } else if (isred(p)) { /* 2.3d */
  909. X      single_rotate(s, il);
  910. X      single_rotate(p, !il);
  911. X      setblack(x);
  912. X      setred(s);
  913. X      return;
  914. X    } else {  /* 2.3e */
  915. X      single_rotate(s, il);
  916. X      single_rotate(p, !il);
  917. X      setblack(x);
  918. X      return;
  919. X    }
  920. X  }
  921. X}
  922. X
  923. X
  924. Xrb_print_tree(t, level)
  925. XRb_node t;
  926. Xint level;
  927. X{
  928. X  int i;
  929. X  if (ishead(t) && t->p.parent == t) {
  930. X    printf("tree 0x%x is empty\n", t);
  931. X  } else if (ishead(t)) {
  932. X    printf("Head: 0x%x.  Root = 0x%x\n", t, t->p.root);
  933. X    rb_print_tree(t->p.root, 0);
  934. X  } else {
  935. X    if (isext(t)) {
  936. X      for (i = 0; i < level; i++) putchar(' ');
  937. X      printf("Ext node 0x%x: %c,%c: p=0x%x, k=%s\n", 
  938. X              t, isred(t)?'R':'B', isleft(t)?'l':'r', t->p.parent, t->k.key);
  939. X    } else {
  940. X      rb_print_tree(t->c.child.left, level+2);
  941. X      rb_print_tree(t->c.child.right, level+2);
  942. X      for (i = 0; i < level; i++) putchar(' ');
  943. X      printf("Int node 0x%x: %c,%c: l=0x%x, r=0x%x, p=0x%x, lr=(%s,%s)\n", 
  944. X              t, isred(t)?'R':'B', isleft(t)?'l':'r', t->c.child.left, 
  945. X              t->c.child.right, 
  946. X              t->p.parent, t->k.lext->k.key, t->v.rext->k.key);
  947. X    }
  948. X  }
  949. X}
  950. X
  951. Xrb_iprint_tree(t, level)
  952. XRb_node t;
  953. Xint level;
  954. X{
  955. X  int i;
  956. X  if (ishead(t) && t->p.parent == t) {
  957. X    printf("tree 0x%x is empty\n", t);
  958. X  } else if (ishead(t)) {
  959. X    printf("Head: 0x%x.  Root = 0x%x, < = 0x%x, > = 0x%x\n", 
  960. X            t, t->p.root, t->c.list.blink, t->c.list.flink);
  961. X    rb_iprint_tree(t->p.root, 0);
  962. X  } else {
  963. X    if (isext(t)) {
  964. X      for (i = 0; i < level; i++) putchar(' ');
  965. X      printf("Ext node 0x%x: %c,%c: p=0x%x, <=0x%x, >=0x%x k=%d\n", 
  966. X              t, isred(t)?'R':'B', isleft(t)?'l':'r', t->p.parent, 
  967. X              t->c.list.blink, t->c.list.flink, t->k.ikey);
  968. X    } else {
  969. X      rb_iprint_tree(t->c.child.left, level+2);
  970. X      rb_iprint_tree(t->c.child.right, level+2);
  971. X      for (i = 0; i < level; i++) putchar(' ');
  972. X      printf("Int node 0x%x: %c,%c: l=0x%x, r=0x%x, p=0x%x, lr=(%d,%d)\n", 
  973. X              t, isred(t)?'R':'B', isleft(t)?'l':'r', t->c.child.left, 
  974. X              t->c.child.right, 
  975. X              t->p.parent, t->k.lext->k.ikey, t->v.rext->k.ikey);
  976. X    }
  977. X  }
  978. X}
  979. X      
  980. Xrb_nblack(n)
  981. XRb_node(n);
  982. X{
  983. X  int nb;
  984. X  if (ishead(n) || isint(n)) {
  985. X    fprintf(stderr, "ERROR: rb_nblack called on a non-external node 0x%x\n",
  986. X            n);
  987. X    exit(1);
  988. X  }
  989. X  nb = 0;
  990. X  while(!ishead(n)) {
  991. X    if (isblack(n)) nb++;
  992. X    n = n->p.parent;
  993. X  }
  994. X  return nb;
  995. X}
  996. X
  997. Xrb_plength(n)
  998. XRb_node(n);
  999. X{
  1000. X  int pl;
  1001. X  if (ishead(n) || isint(n)) {
  1002. X    fprintf(stderr, "ERROR: rb_plength called on a non-external node 0x%x\n",
  1003. X            n);
  1004. X    exit(1);
  1005. X  }
  1006. X  pl = 0;
  1007. X  while(!ishead(n)) {
  1008. X    pl++;
  1009. X    n = n->p.parent;
  1010. X  }
  1011. X  return pl;
  1012. X}
  1013. X
  1014. Xrb_free_tree(n)
  1015. XRb_node(n);
  1016. X{
  1017. X  if (!ishead(n)) {
  1018. X    fprintf(stderr, "ERROR: Rb_free_tree called on a non-head node\n");
  1019. X    exit(1);
  1020. X  }
  1021. X
  1022. X  while(rb_first(n) != nil(n)) {
  1023. X    rb_delete_node(rb_first(n));
  1024. X  }
  1025. X  free(n);
  1026. X}
  1027. X
  1028. Xchar *rb_val(n)
  1029. XRb_node(n);
  1030. X{
  1031. X  return n->v.val;
  1032. X}
  1033. END_OF_FILE
  1034.   if test 11987 -ne `wc -c <'rb.c'`; then
  1035.     echo shar: \"'rb.c'\" unpacked with wrong size!
  1036.   fi
  1037.   # end of 'rb.c'
  1038. fi
  1039. if test -f 'rb.h' -a "${1}" != "-c" ; then 
  1040.   echo shar: Will not clobber existing file \"'rb.h'\"
  1041. else
  1042.   echo shar: Extracting \"'rb.h'\" \(1839 characters\)
  1043.   sed "s/^X//" >'rb.h' <<'END_OF_FILE'
  1044. Xtypedef struct {
  1045. X  unsigned red : 1 ;
  1046. X  unsigned internal : 1 ;
  1047. X  unsigned left : 1 ;
  1048. X  unsigned root : 1 ;
  1049. X  unsigned head : 1 ;
  1050. X} status;
  1051. X
  1052. Xtypedef struct rb_node {
  1053. X  union {
  1054. X    struct {
  1055. X      struct rb_node *flink;
  1056. X      struct rb_node *blink;
  1057. X    } list;
  1058. X    struct {
  1059. X      struct rb_node *left;
  1060. X      struct rb_node *right;
  1061. X    } child;
  1062. X  } c;
  1063. X  union {
  1064. X    struct rb_node *parent;
  1065. X    struct rb_node *root;
  1066. X  } p;
  1067. X  status s;
  1068. X  union {
  1069. X    int ikey;
  1070. X    char *key;
  1071. X    struct rb_node *lext;
  1072. X  } k;
  1073. X  union {
  1074. X    char *val;
  1075. X    struct rb_node *rext;
  1076. X  } v;
  1077. X} *Rb_node;
  1078. X
  1079. Xextern Rb_node make_rb();
  1080. Xextern Rb_node rb_insert_b(/* node, char *key, char *value */);
  1081. X
  1082. Xextern Rb_node rb_find_key(/* tree, char *key */);
  1083. Xextern Rb_node rb_find_ikey(/* tree, int ikey */);
  1084. Xextern Rb_node rb_find_gkey(/* tree, char *key, cmpfxn */);
  1085. X
  1086. Xextern Rb_node rb_find_key_n(/* tree, char *key, int *found */);
  1087. Xextern Rb_node rb_find_ikey_n(/* tree, int ikey, int *found */);
  1088. Xextern Rb_node rb_find_gkey_n(/* tree, char *key, cmpfxn, int *found */);
  1089. Xextern rb_delete_node(/* node */);
  1090. Xextern rb_free_tree(/* node */);  /* Deletes and frees an entire tree */
  1091. Xextern char *rb_val(/* node */);  /* Returns node->v.val (this is to shut
  1092. X                     lint up */
  1093. X
  1094. X#define rb_insert_a(n, k, v) rb_insert_b(n->c.list.flink, k, v)
  1095. X#define rb_insert(t, k, v) rb_insert_b(rb_find_key(t, k), k, v)
  1096. X#define rb_inserti(t, k, v) rb_insert_b(rb_find_ikey(t, k), (char *) k, v)
  1097. X#define rb_insertg(t, k, v, f) rb_insert_b(rb_find_gkey(t, k, f), k, v)
  1098. X#define rb_first(n) (n->c.list.flink)
  1099. X#define rb_last(n) (n->c.list.blink)
  1100. X#define rb_next(n) (n->c.list.flink)
  1101. X#define rb_prev(n) (n->c.list.blink)
  1102. X#define rb_empty(t) (t->c.list.flink == t)
  1103. X#ifndef nil
  1104. X#define nil(t) (t)
  1105. X#endif
  1106. X
  1107. X#define rb_traverse(ptr, lst) \
  1108. X  for(ptr = rb_first(lst); ptr != nil(lst); ptr = rb_next(ptr))
  1109. X
  1110. END_OF_FILE
  1111.   if test 1839 -ne `wc -c <'rb.h'`; then
  1112.     echo shar: \"'rb.h'\" unpacked with wrong size!
  1113.   fi
  1114.   # end of 'rb.h'
  1115. fi
  1116. echo shar: End of archive 1 \(of 1\).
  1117. cp /dev/null ark1isdone
  1118. MISSING=""
  1119. for I in 1 ; do
  1120.     if test ! -f ark${I}isdone ; then
  1121.     MISSING="${MISSING} ${I}"
  1122.     fi
  1123. done
  1124. if test "${MISSING}" = "" ; then
  1125.     echo You have the archive.
  1126.     rm -f ark[1-9]isdone
  1127. else
  1128.     echo You still must unpack the following archives:
  1129.     echo "        " ${MISSING}
  1130. fi
  1131. exit 0
  1132. exit 0 # Just in case...
  1133.