/* Deletes from |tree| and returns an item matching |item|. Returns a null pointer if no matching item found. */ void * prb_delete (struct prb_table *tree, const void *item) { struct prb_node *p; /* Node to delete. */ struct prb_node *q; /* Parent of |p|. */ struct prb_node *f; /* Node at which we are rebalancing. */ int dir; /* Side of |q| on which |p| is a child; side of |f| from which node was deleted. */ assert (tree != NULL && item != NULL); if (tree->prb_root == NULL) return NULL; p = tree->prb_root; for (;;) { int cmp = tree->prb_compare (item, p->prb_data, tree->prb_param); if (cmp == 0) break; dir = cmp > 0; p = p->prb_link[dir]; if (p == NULL) return NULL; } item = p->prb_data; q = p->prb_parent; if (q == NULL) { q = (struct prb_node *) &tree->prb_root; dir = 0; } if (p->prb_link[1] == NULL) { q->prb_link[dir] = p->prb_link[0]; if (q->prb_link[dir] != NULL) q->prb_link[dir]->prb_parent = p->prb_parent; f = q; } else { enum prb_color t; struct prb_node *r = p->prb_link[1]; if (r->prb_link[0] == NULL) { r->prb_link[0] = p->prb_link[0]; q->prb_link[dir] = r; r->prb_parent = p->prb_parent; if (r->prb_link[0] != NULL) r->prb_link[0]->prb_parent = r; t = p->prb_color; p->prb_color = r->prb_color; r->prb_color = t; f = r; dir = 1; } else { struct prb_node *s = r->prb_link[0]; while (s->prb_link[0] != NULL) s = s->prb_link[0]; r = s->prb_parent; r->prb_link[0] = s->prb_link[1]; s->prb_link[0] = p->prb_link[0]; s->prb_link[1] = p->prb_link[1]; q->prb_link[dir] = s; if (s->prb_link[0] != NULL) s->prb_link[0]->prb_parent = s; s->prb_link[1]->prb_parent = s; s->prb_parent = p->prb_parent; if (r->prb_link[0] != NULL) r->prb_link[0]->prb_parent = r; t = p->prb_color; p->prb_color = s->prb_color; s->prb_color = t; f = r; dir = 0; } } if (p->prb_color == PRB_BLACK) { for (;;) { struct prb_node *x; /* Node we want to recolor black if possible. */ struct prb_node *g; /* Parent of |f|. */ struct prb_node *t; /* Temporary for use in finding parent. */ x = f->prb_link[dir]; if (x != NULL && x->prb_color == PRB_RED) { x->prb_color = PRB_BLACK; break; } if (f == (struct prb_node *) &tree->prb_root) break; g = f->prb_parent; if (g == NULL) g = (struct prb_node *) &tree->prb_root; if (dir == 0) { struct prb_node *w = f->prb_link[1]; if (w->prb_color == PRB_RED) { w->prb_color = PRB_BLACK; f->prb_color = PRB_RED; f->prb_link[1] = w->prb_link[0]; w->prb_link[0] = f; g->prb_link[g->prb_link[0] != f] = w; w->prb_parent = f->prb_parent; f->prb_parent = w; g = w; w = f->prb_link[1]; w->prb_parent = f; } if ((w->prb_link[0] == NULL || w->prb_link[0]->prb_color == PRB_BLACK) && (w->prb_link[1] == NULL || w->prb_link[1]->prb_color == PRB_BLACK)) { w->prb_color = PRB_RED; } else { if (w->prb_link[1] == NULL || w->prb_link[1]->prb_color == PRB_BLACK) { struct prb_node *y = w->prb_link[0]; y->prb_color = PRB_BLACK; w->prb_color = PRB_RED; w->prb_link[0] = y->prb_link[1]; y->prb_link[1] = w; if (w->prb_link[0] != NULL) w->prb_link[0]->prb_parent = w; w = f->prb_link[1] = y; w->prb_link[1]->prb_parent = w; } w->prb_color = f->prb_color; f->prb_color = PRB_BLACK; w->prb_link[1]->prb_color = PRB_BLACK; f->prb_link[1] = w->prb_link[0]; w->prb_link[0] = f; g->prb_link[g->prb_link[0] != f] = w; w->prb_parent = f->prb_parent; f->prb_parent = w; if (f->prb_link[1] != NULL) f->prb_link[1]->prb_parent = f; break; } } else { struct prb_node *w = f->prb_link[0]; if (w->prb_color == PRB_RED) { w->prb_color = PRB_BLACK; f->prb_color = PRB_RED; f->prb_link[0] = w->prb_link[1]; w->prb_link[1] = f; g->prb_link[g->prb_link[0] != f] = w; w->prb_parent = f->prb_parent; f->prb_parent = w; g = w; w = f->prb_link[0]; w->prb_parent = f; } if ((w->prb_link[0] == NULL || w->prb_link[0]->prb_color == PRB_BLACK) && (w->prb_link[1] == NULL || w->prb_link[1]->prb_color == PRB_BLACK)) { w->prb_color = PRB_RED; } else { if (w->prb_link[0] == NULL || w->prb_link[0]->prb_color == PRB_BLACK) { struct prb_node *y = w->prb_link[1]; y->prb_color = PRB_BLACK; w->prb_color = PRB_RED; w->prb_link[1] = y->prb_link[0]; y->prb_link[0] = w; if (w->prb_link[1] != NULL) w->prb_link[1]->prb_parent = w; w = f->prb_link[0] = y; w->prb_link[0]->prb_parent = w; } w->prb_color = f->prb_color; f->prb_color = PRB_BLACK; w->prb_link[0]->prb_color = PRB_BLACK; f->prb_link[0] = w->prb_link[1]; w->prb_link[1] = f; g->prb_link[g->prb_link[0] != f] = w; w->prb_parent = f->prb_parent; f->prb_parent = w; if (f->prb_link[0] != NULL) f->prb_link[0]->prb_parent = f; break; } } t = f; f = f->prb_parent; if (f == NULL) f = (struct prb_node *) &tree->prb_root; dir = f->prb_link[0] != t; } } tree->prb_alloc->libavl_free (tree->prb_alloc, p); tree->prb_count--; return (void *) item; }