/* Revision 1.2. Jim Plank */ /* Original code by Jim Plank (plank@cs.utk.edu) */ /* modified for THINK C 6.0 for Macintosh by Chris Bartley */ #include #include #include #include #include "jrb.h" static void mk_new_int (JRB l, JRB r, JRB p, int il); static JRB lprev (JRB n); static JRB rprev (JRB n); static void recolor (JRB n); static void single_rotate (JRB y, int l); static void jrb_print_tree (JRB t, int level); static void jrb_iprint_tree (JRB t, int level); #define isred(n) (n->red) #define isblack(n) (!isred(n)) #define isleft(n) (n->left) #define isright(n) (!isleft(n)) #define isint(n) (n->internal) #define isext(n) (!isint(n)) #define ishead(n) (n->roothead & 2) #define isroot(n) (n->roothead & 1) #define getlext(n) ((struct jrb_node *)(n->key.v)) #define setlext(node, val) node->key.v = (void *) (val) #define getrext(n) ((struct jrb_node *)(n->val.v)) #define setrext(node, value) node->val.v = (void *) (value) #define setred(n) n->red = 1 #define setblack(n) n->red = 0 #define setleft(n) n->left = 1 #define setright(n) n->left = 0 #define sethead(n) (n->roothead |= 2) #define setroot(n) (n->roothead |= 1) #define setint(n) n->internal = 1 #define setext(n) n->internal = 0 #define setnormal(n) n->roothead = 0 #define sibling(n) ((isleft(n)) ? n->parent->blink : n->parent->flink) static void insert (JRB item, JRB list) /* Inserts to the end of a list */ { JRB last_node; last_node = list->blink; list->blink = item; last_node->flink = item; item->blink = last_node; item->flink = list; } static void delete_item (JRB item) /* Deletes an arbitrary iterm */ { item->flink->blink = item->blink; item->blink->flink = item->flink; } #define mk_new_ext(new, kkkey, vvval) {\ new = (JRB) malloc(sizeof(struct jrb_node));\ new->val = vvval;\ new->key = kkkey;\ setext(new);\ setblack(new);\ setnormal(new);\ } static void mk_new_int (JRB l, JRB r, JRB p, int il) { JRB newnode; newnode = (JRB) malloc (sizeof (struct jrb_node)); setint (newnode); setred (newnode); setnormal (newnode); newnode->flink = l; newnode->blink = r; newnode->parent = p; setlext (newnode, l); setrext (newnode, r); l->parent = newnode; r->parent = newnode; setleft (l); setright (r); if (ishead (p)) { p->parent = newnode; setroot (newnode); } else if (il) { setleft (newnode); p->flink = newnode; } else { setright (newnode); p->blink = newnode; } recolor (newnode); } JRB lprev (JRB n) { if (ishead (n)) return n; while (!isroot (n)) { if (isright (n)) return n->parent; n = n->parent; } return n->parent; } JRB rprev (JRB n) { if (ishead (n)) return n; while (!isroot (n)) { if (isleft (n)) return n->parent; n = n->parent; } return n->parent; } JRB make_jrb () { JRB head; head = (JRB) malloc (sizeof (struct jrb_node)); head->flink = head; head->blink = head; head->parent = head; head->key.s = ""; sethead (head); return head; } JRB jrb_find_gte_str (JRB n, char *key, int *fnd) { int cmp; *fnd = 0; if (!ishead (n)) { fprintf (stderr, "jrb_find_gte_str called on non-head 0x%x\n", (int) n); exit (1); } if (n->parent == n) return n; cmp = strcmp (key, n->blink->key.s); if (cmp == 0) { *fnd = 1; return n->blink; } if (cmp > 0) return n; else n = n->parent; while (1) { if (isext (n)) return n; cmp = strcmp (key, getlext (n)->key.s); if (cmp == 0) { *fnd = 1; return getlext (n); } if (cmp < 0) n = n->flink; else n = n->blink; } } JRB jrb_find_str (JRB n, char *key) { int fnd; JRB j; j = jrb_find_gte_str (n, key, &fnd); if (fnd) return j; else return NULL; } JRB jrb_find_gte_int (JRB n, int ikey, int *fnd) { *fnd = 0; if (!ishead (n)) { fprintf (stderr, "jrb_find_gte_int called on non-head 0x%x\n", (unsigned int) n); exit (1); } if (n->parent == n) return n; if (ikey == n->blink->key.i) { *fnd = 1; return n->blink; } if (ikey > n->blink->key.i) return n; else n = n->parent; while (1) { if (isext (n)) return n; if (ikey == getlext (n)->key.i) { *fnd = 1; return getlext (n); } n = (ikey < getlext (n)->key.i) ? n->flink : n->blink; } } JRB jrb_find_int (JRB n, int ikey) { int fnd; JRB j; j = jrb_find_gte_int (n, ikey, &fnd); if (fnd) return j; else return NULL; } JRB jrb_find_gte_dbl (JRB n, double dkey, int *fnd) { *fnd = 0; if (!ishead (n)) { fprintf (stderr, "jrb_find_gte_dbl called on non-head 0x%x\n", (unsigned int) n); exit (1); } if (n->parent == n) return n; if (dkey == n->blink->key.d) { *fnd = 1; return n->blink; } if (dkey > n->blink->key.d) return n; else n = n->parent; while (1) { if (isext (n)) return n; if (dkey == getlext (n)->key.d) { *fnd = 1; return getlext (n); } n = (dkey < getlext (n)->key.d) ? n->flink : n->blink; } } JRB jrb_find_dbl (JRB n, double dkey) { int fnd; JRB j; j = jrb_find_gte_dbl (n, dkey, &fnd); if (fnd) return j; else return NULL; } JRB jrb_find_gte_gen (JRB n, Jval key, int (*fxn) (Jval, Jval), int *fnd) { int cmp; *fnd = 0; if (!ishead (n)) { fprintf (stderr, "jrb_find_gte_str called on non-head 0x%x\n", (unsigned int) n); exit (1); } if (n->parent == n) return n; cmp = (*fxn) (key, n->blink->key); if (cmp == 0) { *fnd = 1; return n->blink; } if (cmp > 0) return n; else n = n->parent; while (1) { if (isext (n)) return n; cmp = (*fxn) (key, getlext (n)->key); if (cmp == 0) { *fnd = 1; return getlext (n); } if (cmp < 0) n = n->flink; else n = n->blink; } } JRB jrb_find_gen (JRB n, Jval key, int (*fxn) (Jval, Jval)) { int fnd; JRB j; j = jrb_find_gte_gen (n, key, fxn, &fnd); if (fnd) return j; else return NULL; } static JRB jrb_insert_b (JRB n, Jval key, Jval val) { JRB newleft, newright, newnode, p; if (ishead (n)) { if (n->parent == n) { /* Tree is empty */ mk_new_ext (newnode, key, val); insert (newnode, n); n->parent = newnode; newnode->parent = n; setroot (newnode); return newnode; } else { mk_new_ext (newright, key, val); insert (newright, n); newleft = newright->blink; setnormal (newleft); mk_new_int (newleft, newright, newleft->parent, isleft (newleft)); p = rprev (newright); if (!ishead (p)) setlext (p, newright); return newright; } } else { mk_new_ext (newleft, key, val); insert (newleft, n); setnormal (n); mk_new_int (newleft, n, n->parent, isleft (n)); p = lprev (newleft); if (!ishead (p)) setrext (p, newleft); return newleft; } } static void recolor (JRB n) { JRB p, gp, s; int done = 0; while (!done) { if (isroot (n)) { setblack (n); return; } p = n->parent; if (isblack (p)) return; if (isroot (p)) { setblack (p); return; } gp = p->parent; s = sibling (p); if (isred (s)) { setblack (p); setred (gp); setblack (s); n = gp; } else { done = 1; } } /* p's sibling is black, p is red, gp is black */ if ((isleft (n) == 0) == (isleft (p) == 0)) { single_rotate (gp, isleft (n)); setblack (p); setred (gp); } else { single_rotate (p, isleft (n)); single_rotate (gp, isleft (n)); setblack (n); setred (gp); } } static void single_rotate (JRB y, int l) { int rl, ir; JRB x, yp; ir = isroot (y); yp = y->parent; if (!ir) { rl = isleft (y); } if (l) { x = y->flink; y->flink = x->blink; setleft (y->flink); y->flink->parent = y; x->blink = y; setright (y); } else { x = y->blink; y->blink = x->flink; setright (y->blink); y->blink->parent = y; x->flink = y; setleft (y); } x->parent = yp; y->parent = x; if (ir) { yp->parent = x; setnormal (y); setroot (x); } else { if (rl) { yp->flink = x; setleft (x); } else { yp->blink = x; setright (x); } } } void jrb_delete_node (JRB n) { JRB s, p, gp; char ir; if (isint (n)) { fprintf (stderr, "Cannot delete an internal node: 0x%x\n", (unsigned int) n); exit (1); } if (ishead (n)) { fprintf (stderr, "Cannot delete the head of an jrb_tree: 0x%x\n", (unsigned int) n); exit (1); } delete_item (n); /* Delete it from the list */ p = n->parent; /* The only node */ if (isroot (n)) { p->parent = p; free (n); return; } s = sibling (n); /* The only node after deletion */ if (isroot (p)) { s->parent = p->parent; s->parent->parent = s; setroot (s); free (p); free (n); return; } gp = p->parent; /* Set parent to sibling */ s->parent = gp; if (isleft (p)) { gp->flink = s; setleft (s); } else { gp->blink = s; setright (s); } ir = isred (p); free (p); free (n); if (isext (s)) { /* Update proper rext and lext values */ p = lprev (s); if (!ishead (p)) setrext (p, s); p = rprev (s); if (!ishead (p)) setlext (p, s); } else if (isblack (s)) { fprintf (stderr, "DELETION PROB -- sib is black, internal\n"); exit (1); } else { p = lprev (s); if (!ishead (p)) setrext (p, s->flink); p = rprev (s); if (!ishead (p)) setlext (p, s->blink); setblack (s); return; } if (ir) return; /* Recolor */ n = s; p = n->parent; s = sibling (n); while (isblack (p) && isblack (s) && isint (s) && isblack (s->flink) && isblack (s->blink)) { setred (s); n = p; if (isroot (n)) return; p = n->parent; s = sibling (n); } if (isblack (p) && isred (s)) { /* Rotation 2.3b */ single_rotate (p, isright (n)); setred (p); setblack (s); s = sibling (n); } { JRB x, z; char il; if (isext (s)) { fprintf (stderr, "DELETION ERROR: sibling not internal\n"); exit (1); } il = isleft (n); x = il ? s->flink : s->blink; z = sibling (x); if (isred (z)) { /* Rotation 2.3f */ single_rotate (p, !il); setblack (z); if (isred (p)) setred (s); else setblack (s); setblack (p); } else if (isblack (x)) { /* Recoloring only (2.3c) */ if (isred (s) || isblack (p)) { fprintf (stderr, "DELETION ERROR: 2.3c not quite right\n"); exit (1); } setblack (p); setred (s); return; } else if (isred (p)) { /* 2.3d */ single_rotate (s, il); single_rotate (p, !il); setblack (x); setred (s); return; } else { /* 2.3e */ single_rotate (s, il); single_rotate (p, !il); setblack (x); return; } } } void jrb_print_tree (JRB t, int level) { int i; if (ishead (t) && t->parent == t) { printf ("tree 0x%x is empty\n", (unsigned int) t); } else if (ishead (t)) { printf ("Head: 0x%x. Root = 0x%x\n", (unsigned int) t, (unsigned int) t->parent); jrb_print_tree (t->parent, 0); } else { if (isext (t)) { for (i = 0; i < level; i++) putchar (' '); printf ("Ext node 0x%x: %c,%c: p=0x%x, k=%s\n", (unsigned int) t, isred (t) ? 'R' : 'B', isleft (t) ? 'l' : 'r', (unsigned int) t->parent, t->key.s); } else { jrb_print_tree (t->flink, level + 2); jrb_print_tree (t->blink, level + 2); for (i = 0; i < level; i++) putchar (' '); printf ("Int node 0x%x: %c,%c: l=0x%x, r=0x%x, p=0x%x, lr=(%s,%s)\n", (unsigned int) t, isred (t) ? 'R' : 'B', isleft (t) ? 'l' : 'r', (unsigned int) t->flink, (unsigned int) t->blink, (unsigned int) t->parent, getlext (t)->key.s, getrext (t)->key.s); } } } void jrb_iprint_tree (JRB t, int level) { int i; if (ishead (t) && t->parent == t) { printf ("tree 0x%x is empty\n", (unsigned int) t); } else if (ishead (t)) { printf ("Head: 0x%x. Root = 0x%x, < = 0x%x, > = 0x%x\n", (unsigned int) t, (unsigned int) t->parent, (unsigned int) t->blink, (unsigned int) t->flink); jrb_iprint_tree (t->parent, 0); } else { if (isext (t)) { for (i = 0; i < level; i++) putchar (' '); printf ("Ext node 0x%x: %c,%c: p=0x%x, <=0x%x, >=0x%x k=%d\n", (unsigned int) t, isred (t) ? 'R' : 'B', isleft (t) ? 'l' : 'r', (unsigned int) t->parent, (unsigned int) t->blink, (unsigned int) t->flink, t->key.i); } else { jrb_iprint_tree (t->flink, level + 2); jrb_iprint_tree (t->blink, level + 2); for (i = 0; i < level; i++) putchar (' '); printf ("Int node 0x%x: %c,%c: l=0x%x, r=0x%x, p=0x%x, lr=(%d,%d)\n", (unsigned int) t, isred (t) ? 'R' : 'B', isleft (t) ? 'l' : 'r', (unsigned int) t->flink, (unsigned int) t->blink, (unsigned int) t->parent, getlext (t)->key.i, getrext (t)->key.i); } } } int jrb_nblack (JRB n) { int nb; if (ishead (n) || isint (n)) { fprintf (stderr, "ERROR: jrb_nblack called on a non-external node 0x%x\n", (unsigned int) n); exit (1); } nb = 0; while (!ishead (n)) { if (isblack (n)) nb++; n = n->parent; } return nb; } int jrb_plength (JRB n) { int pl; if (ishead (n) || isint (n)) { fprintf (stderr, "ERROR: jrb_plength called on a non-external node 0x%x\n", (unsigned int) n); exit (1); } pl = 0; while (!ishead (n)) { pl++; n = n->parent; } return pl; } void jrb_free_tree (JRB n) { if (!ishead (n)) { fprintf (stderr, "ERROR: Rb_free_tree called on a non-head node\n"); exit (1); } while (jrb_first (n) != jrb_nil (n)) { jrb_delete_node (jrb_first (n)); } free (n); } Jval jrb_val (JRB n) { return n->val; } /* static JRB jrb_insert_a(JRB nd, Jval key, Jval val) { return jrb_insert_b(nd->flink, key, val); } */ JRB jrb_insert_str (JRB tree, char *key, Jval val) { Jval k; int fnd; k.s = key; return jrb_insert_b (jrb_find_gte_str (tree, key, &fnd), k, val); } JRB jrb_insert_int (JRB tree, int ikey, Jval val) { Jval k; int fnd; k.i = ikey; return jrb_insert_b (jrb_find_gte_int (tree, ikey, &fnd), k, val); } JRB jrb_insert_dbl (JRB tree, double dkey, Jval val) { Jval k; int fnd; k.d = dkey; return jrb_insert_b (jrb_find_gte_dbl (tree, dkey, &fnd), k, val); } JRB jrb_insert_gen (JRB tree, Jval key, Jval val, int (*func) (Jval, Jval)) { int fnd; return jrb_insert_b (jrb_find_gte_gen (tree, key, func, &fnd), key, val); }