int rb_tree_check(struct rb_tree* tree, struct rb_node* node) { int lh, rh; if (node == NULL) return 1; else { struct rb_node *ln = node->link[0]; struct rb_node *rn = node->link[1]; /* Consecutive red links */ if (is_red(node)) { if (is_red(ln) || is_red(rn)) { puts("Red violation"); return 0; } } lh = rb_tree_check(tree, ln); rh = rb_tree_check(tree, rn); /* Invalid binary search tree - not sorted correctly */ if ((ln && tree->compare(ln->key, node->key) >= 0) || (rn && tree->compare(rn->key, node->key) <= 0)) { puts("Binary tree violation"); return 0; } /* Black height mismatch */ if ( lh != 0 && rh != 0 && lh != rh ) { puts ( "Black violation" ); return 0; } /* Only count black links */ if (lh != 0 && rh != 0) return is_red(node) ? lh : lh + 1; else return 0; } }
int rb_tree_insert(struct rb_tree* tree, const void* key, const void* value) { struct rb_node* node; if (tree_search(tree, key)) return 0; node = rb_tree_insert_r(tree, tree->root, key, value); tree->root = node; tree->root->red = 0; tree->elements++; #ifdef RB_TREE_CHECKS rb_tree_check(tree, node); #endif return 1; }
int rb_tree_remove_node(struct rb_tree* tree, const void* key, rb_tree_free_node freecb) { struct rb_node head = {0}; /* False tree root */ struct rb_node *q, *p, *g; /* Helpers */ struct rb_node *f = NULL; /* Found item */ int dir = 1; if (!tree->root) return 0; /* Set up helpers */ q = &head; g = p = NULL; q->link[1] = tree->root; /* Search and push a red down */ while (q->link[dir]) { int last = dir; int res; /* Update helpers */ g = p, p = q; q = q->link[dir]; res = tree->compare(q->key, key); dir = res < 0; /* Save found node */ if (!res) f = q; /* Push the red node down */ if (!is_red(q) && !is_red(q->link[dir])) { if (is_red(q->link[!dir])) p = p->link[last] = rb_tree_rotate_single(q, dir); else if (!is_red(q->link[!dir])) { struct rb_node* s = p->link[!last]; if (s) { if (!is_red(s->link[!last]) && !is_red (s->link[last])) { /* Color flip */ p->red = 0; s->red = 1; q->red = 1; } else { int dir2 = g->link[1] == p; if (is_red(s->link[last])) g->link[dir2] = rb_tree_rotate_double(p, last); else if (is_red(s->link[!last])) g->link[dir2] = rb_tree_rotate_single(p, last); /* Ensure correct coloring */ q->red = g->link[dir2]->red = 1; g->link[dir2]->link[0]->red = 0; g->link[dir2]->link[1]->red = 0; } } } } } /* Replace and remove if found */ if (f) { freecb(f); f->key = q->key; f->value = q->value; p->link[p->link[1] == q] = q->link[q->link[0] == NULL]; tree->free(q); tree->elements--; } /* Update root and make it black */ tree->root = head.link[1]; if (tree->root != NULL) tree->root->red = 0; #ifdef RB_TREE_CHECKS rb_tree_check(tree, tree->root); #endif return f != NULL; }
int main(int argc, char **argv) { int N, M; int *k; double kd; rb_tree t; rb_node *n; int i, j; if (argc < 2) { fprintf(stderr, "Usage: redblack_test Ntest [rand seed]\n"); return 1; } N = atoi(argv[1]); k = (int *) malloc(N * sizeof(int)); rb_tree_init(&t, comp); srand((unsigned) (argc > 2 ? atoi(argv[2]) : time(NULL))); for (i = 0; i < N; ++i) { double *newk = (double *) malloc(sizeof(double)); *newk = (k[i] = rand() % N); if (!rb_tree_insert(&t, newk)) { fprintf(stderr, "error in rb_tree_insert\n"); return 1; } if (!rb_tree_check(&t)) { fprintf(stderr, "rb_tree_check_failed after insert!\n"); return 1; } } if (t.N != N) { fprintf(stderr, "incorrect N (%d) in tree (vs. %d)\n", t.N, N); return 1; } for (i = 0; i < N; ++i) { kd = k[i]; if (!rb_tree_find(&t, &kd)) { fprintf(stderr, "rb_tree_find lost %d!\n", k[i]); return 1; } } n = rb_tree_min(&t); for (i = 0; i < N; ++i) { if (!n) { fprintf(stderr, "not enough successors %d\n!", i); return 1; } printf("%d: %g\n", i, n->k[0]); n = rb_tree_succ(n); } if (n) { fprintf(stderr, "too many successors!\n"); return 1; } n = rb_tree_max(&t); for (i = 0; i < N; ++i) { if (!n) { fprintf(stderr, "not enough predecessors %d\n!", i); return 1; } printf("%d: %g\n", i, n->k[0]); n = rb_tree_pred(n); } if (n) { fprintf(stderr, "too many predecessors!\n"); return 1; } for (M = N; M > 0; --M) { int knew = rand() % N; /* random new key */ j = rand() % M; /* random original key to replace */ for (i = 0; i < N; ++i) if (k[i] >= 0) if (j-- == 0) break; if (i >= N) abort(); kd = k[i]; if (!(n = rb_tree_find(&t, &kd))) { fprintf(stderr, "rb_tree_find lost %d!\n", k[i]); return 1; } n->k[0] = knew; if (!rb_tree_resort(&t, n)) { fprintf(stderr, "error in rb_tree_resort\n"); return 1; } if (!rb_tree_check(&t)) { fprintf(stderr, "rb_tree_check_failed after change %d!\n", N - M + 1); return 1; } k[i] = -1 - knew; } if (t.N != N) { fprintf(stderr, "incorrect N (%d) in tree (vs. %d)\n", t.N, N); return 1; } for (i = 0; i < N; ++i) k[i] = -1 - k[i]; /* undo negation above */ for (i = 0; i < N; ++i) { rb_node *le, *gt; double lek, gtk; kd = 0.01 * (rand() % (N * 150) - N * 25); le = rb_tree_find_le(&t, &kd); gt = rb_tree_find_gt(&t, &kd); n = rb_tree_min(&t); lek = le ? le->k[0] : -HUGE_VAL; gtk = gt ? gt->k[0] : +HUGE_VAL; printf("%g <= %g < %g\n", lek, kd, gtk); if (n->k[0] > kd) { if (le) { fprintf(stderr, "found invalid le %g for %g\n", lek, kd); return 1; } if (gt != n) { fprintf(stderr, "gt is not first node for k=%g\n", kd); return 1; } } else { rb_node *succ = n; do { n = succ; succ = rb_tree_succ(n); } while (succ && succ->k[0] <= kd); if (n != le) { fprintf(stderr, "rb_tree_find_le gave wrong result for k=%g\n", kd); return 1; } if (succ != gt) { fprintf(stderr, "rb_tree_find_gt gave wrong result for k=%g\n", kd); return 1; } } } for (M = N; M > 0; --M) { j = rand() % M; for (i = 0; i < N; ++i) if (k[i] >= 0) if (j-- == 0) break; if (i >= N) abort(); kd = k[i]; if (!(n = rb_tree_find(&t, &kd))) { fprintf(stderr, "rb_tree_find lost %d!\n", k[i]); return 1; } n = rb_tree_remove(&t, n); free(n->k); free(n); if (!rb_tree_check(&t)) { fprintf(stderr, "rb_tree_check_failed after remove!\n"); return 1; } k[i] = -1 - k[i]; } if (t.N != 0) { fprintf(stderr, "nonzero N (%d) in tree at end\n", t.N); return 1; } rb_tree_destroy(&t); free(k); printf("SUCCESS.\n"); return 0; }