1 /* Copyright (c) 2007-2014 Massachusetts Institute of Technology
3 * Permission is hereby granted, free of charge, to any person obtaining
4 * a copy of this software and associated documentation files (the
5 * "Software"), to deal in the Software without restriction, including
6 * without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to
8 * permit persons to whom the Software is furnished to do so, subject to
9 * the following conditions:
11 * The above copyright notice and this permission notice shall be
12 * included in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 /* simple implementation of red-black trees optimized for use with DIRECT */
29 /* it is convenient to use an explicit node for NULL nodes ... we need
30 to be careful never to change this node indirectly via one of our
32 rb_node nil = { &nil, &nil, &nil, 0, BLACK };
36 void rb_tree_init(rb_tree * t, rb_compare compare)
43 static void destroy(rb_node * n)
52 void rb_tree_destroy(rb_tree * t)
58 void rb_tree_destroy_with_keys(rb_tree * t)
60 rb_node *n = rb_tree_min(t);
69 static void rotate_left(rb_node * p, rb_tree * t)
71 rb_node *n = p->r; /* must be non-NIL */
87 static void rotate_right(rb_node * p, rb_tree * t)
89 rb_node *n = p->l; /* must be non-NIL */
105 static void insert_node(rb_tree * t, rb_node * n)
107 rb_compare compare = t->compare;
109 rb_node *p = t->root;
111 n->p = n->l = n->r = NIL;
118 /* insert (RED) node into tree */
120 if (compare(k, p->k) <= 0) { /* k <= p->k */
139 if (n->p->c == RED) { /* red cannot have red child */
140 rb_node *u = p == p->p->l ? p->p->r : p->p->l;
141 if (u != NIL && u->c == RED) {
144 if ((p = n->p) != NIL) {
149 if (n == p->r && p == p->p->l) {
153 } else if (n == p->l && p == p->p->r) {
160 if (n == p->l && p == p->p->l)
161 rotate_right(p->p, t);
162 else if (n == p->r && p == p->p->r)
163 rotate_left(p->p, t);
169 rb_node *rb_tree_insert(rb_tree * t, rb_key k)
171 rb_node *n = (rb_node *) malloc(sizeof(rb_node));
179 static int check_node(rb_node * n, int *nblack, rb_tree * t)
182 rb_compare compare = t->compare;
187 if (n->r != NIL && n->r->p != n)
189 if (n->r != NIL && compare(n->r->k, n->k) < 0)
191 if (n->l != NIL && n->l->p != n)
193 if (n->l != NIL && compare(n->l->k, n->k) > 0)
196 if (n->r != NIL && n->r->c == RED)
198 if (n->l != NIL && n->l->c == RED)
201 if (!(check_node(n->r, &nbl, t) && check_node(n->l, &nbr, t)))
205 *nblack = nbl + (n->c == BLACK);
209 int rb_tree_check(rb_tree * t)
214 if (nil.p != NIL || nil.r != NIL || nil.l != NIL)
218 if (t->root->c != BLACK)
220 return check_node(t->root, &nblack, t);
223 rb_node *rb_tree_find(rb_tree * t, rb_key k)
225 rb_compare compare = t->compare;
226 rb_node *p = t->root;
228 int comp = compare(k, p->k);
231 p = comp <= 0 ? p->l : p->r;
236 /* find greatest point in subtree p that is <= k */
237 static rb_node *find_le(rb_node * p, rb_key k, rb_tree * t)
239 rb_compare compare = t->compare;
241 if (compare(p->k, k) <= 0) { /* p->k <= k */
242 rb_node *r = find_le(p->r, k, t);
247 } else /* p->k > k */
250 return NULL; /* k < everything in subtree */
253 /* find greatest point in t <= k */
254 rb_node *rb_tree_find_le(rb_tree * t, rb_key k)
256 return find_le(t->root, k, t);
259 /* find greatest point in subtree p that is < k */
260 static rb_node *find_lt(rb_node * p, rb_key k, rb_tree * t)
262 rb_compare compare = t->compare;
264 if (compare(p->k, k) < 0) { /* p->k < k */
265 rb_node *r = find_lt(p->r, k, t);
270 } else /* p->k >= k */
273 return NULL; /* k <= everything in subtree */
276 /* find greatest point in t < k */
277 rb_node *rb_tree_find_lt(rb_tree * t, rb_key k)
279 return find_lt(t->root, k, t);
282 /* find least point in subtree p that is > k */
283 static rb_node *find_gt(rb_node * p, rb_key k, rb_tree * t)
285 rb_compare compare = t->compare;
287 if (compare(p->k, k) > 0) { /* p->k > k */
288 rb_node *l = find_gt(p->l, k, t);
293 } else /* p->k <= k */
296 return NULL; /* k >= everything in subtree */
299 /* find least point in t > k */
300 rb_node *rb_tree_find_gt(rb_tree * t, rb_key k)
302 return find_gt(t->root, k, t);
305 rb_node *rb_tree_min(rb_tree * t)
307 rb_node *n = t->root;
308 while (n != NIL && n->l != NIL)
310 return (n == NIL ? NULL : n);
313 rb_node *rb_tree_max(rb_tree * t)
315 rb_node *n = t->root;
316 while (n != NIL && n->r != NIL)
318 return (n == NIL ? NULL : n);
321 rb_node *rb_tree_succ(rb_node * n)
330 } while (prev == n->r && n != NIL);
331 return n == NIL ? NULL : n;
340 rb_node *rb_tree_pred(rb_node * n)
349 } while (prev == n->l && n != NIL);
350 return n == NIL ? NULL : n;
359 rb_node *rb_tree_remove(rb_tree * t, rb_node * n)
363 if (n->l != NIL && n->r != NIL) {
364 rb_node *lmax = n->l;
365 while (lmax->r != NIL)
370 m = n->l != NIL ? n->l : n->r;
387 rb_node *s = m == mp->l ? mp->r : mp->l;
395 s = m == mp->l ? mp->r : mp->l;
397 if (mp->c == BLACK && s->c == BLACK && s->l->c == BLACK && s->r->c == BLACK) {
403 } else if (mp->c == RED && s->c == BLACK && s->l->c == BLACK && s->r->c == BLACK) {
408 if (m == mp->l && s->c == BLACK && s->l->c == RED && s->r->c == BLACK) {
412 s = m == mp->l ? mp->r : mp->l;
413 } else if (m == mp->r && s->c == BLACK && s->r->c == RED && s->l->c == BLACK) {
417 s = m == mp->l ? mp->r : mp->l;
433 n->k = k; /* n may have changed during remove */
434 return n; /* the node that was deleted may be different from initial n */
437 rb_node *rb_tree_resort(rb_tree * t, rb_node * n)
439 n = rb_tree_remove(t, n);
444 /* shift all key pointers by kshift ... this is useful when the keys
445 are pointers into another array, that has been resized with realloc */
446 static void shift_keys(rb_node * n, ptrdiff_t kshift)
447 { /* assumes n != NIL */
450 shift_keys(n->l, kshift);
452 shift_keys(n->r, kshift);
455 void rb_tree_shift_keys(rb_tree * t, ptrdiff_t kshift)
458 shift_keys(t->root, kshift);