2 rbl.c -- red-black tree + linked list convenience
3 Copyright (C) 2000 Ivo Timmermans <itimmermans@bigfoot.com>,
4 2000 Guus Sliepen <guus@sliepen.warande.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 $Id: rbl.c,v 1.1.2.12 2000/11/24 23:12:59 guus Exp $
31 /* Allocate a new rbl node */
34 return (rbl_t *)xmalloc_and_zero(sizeof(rbl_t));
38 void free_rbl(rbl_t *rbl)
40 if(rbl->data && rbl->tree->delete)
41 rbl->tree->delete(rbl->data);
45 /* Allocate a new rbltree header */
46 rbltree_t *new_rbltree(rbl_compare_t compare, rbl_action_t delete)
50 tree = (rbltree_t *)xmalloc_and_zero(sizeof(rbltree_t));
53 tree->compare = compare;
54 tree->delete = delete;
60 /* Free a rbltree header */
61 void free_rbltree(rbltree_t *tree)
66 /* Search closest match in the tree */
67 rbl_t *rbl_search_closest_rbl(rbltree_t *tree, void *data)
72 next = rbl = tree->top;
78 result = tree->compare(data, rbl->data);
91 /* Search closest match in the tree */
92 rbl_t *rbl_search_closest_greater_rbl(rbltree_t *tree, void *data)
96 rbl = rbl_search_closest_rbl(tree, data);
100 if(tree->compare(data, rbl->data) > 0)
107 /* Search closest match in the tree */
108 rbl_t *rbl_search_closest_smaller_rbl(rbltree_t *tree, void *data)
112 rbl = rbl_search_closest_rbl(tree, data);
116 if(tree->compare(data, rbl->data) < 0)
123 void *rbl_search_closest(rbltree_t *tree, void *data)
127 rbl = rbl_search_closest_rbl(tree, data);
135 void *rbl_search_closest_greater(rbltree_t *tree, void *data)
139 rbl = rbl_search_closest_greater_rbl(tree, data);
147 void *rbl_search_closest_smaller(rbltree_t *tree, void *data)
151 rbl = rbl_search_closest_smaller_rbl(tree, data);
159 /* Search exact match or return NULL pointer */
160 rbl_t *rbl_search_rbl(rbltree_t *tree, void *data)
169 result = tree->compare(data, rbl->data);
182 void *rbl_search(rbltree_t *tree, void *data)
186 rbl = rbl_search_rbl(tree, data);
194 /* Red-black tree operations taken from Introduction to Algorithms,
195 Cormen, Leiserson & Rivest, chapter 14.
198 void rbl_left_rotate(rbl_t *x)
208 y->parent = x->parent;
213 if(x == x->parent->left)
216 x->parent->right = y;
222 void rbl_right_rotate(rbl_t *y)
230 x->right->parent = y;
232 x->parent = y->parent;
237 if(y == y->parent->right)
238 y->parent->right = x;
246 /* Insert a node into the rbl tree */
247 rbl_t *rbl_insert_rbl(rbltree_t *tree, rbl_t *rbl)
249 rbl_t *closest, *x, *y;
254 /* Binary tree and linked list insert */
258 closest = rbl_search_closest_rbl(tree, rbl->data);
259 result = tree->compare(rbl->data, closest->data);
264 rbl->prev = closest->prev;
269 rbl->prev->next = rbl;
275 closest->right = rbl;
277 rbl->next = closest->next;
282 rbl->next->prev = rbl;
287 return closest; /* Ofcourse, we cannot add two identical things */
289 rbl->parent = closest;
298 /* Red-black part of insert */
303 while(x != tree->top && x->parent->color == RBL_RED)
305 if(x->parent == x->parent->parent->left)
307 y = x->parent->parent->right;
308 if(y && y->color == RBL_RED)
310 x->parent->color = RBL_BLACK;
311 y->color = RBL_BLACK;
312 x->parent->parent->color = RBL_RED;
313 x = x->parent->parent;
317 if(x == x->parent->right)
322 x->parent->color = RBL_BLACK;
323 x->parent->parent->color = RBL_RED;
324 rbl_right_rotate(x->parent->parent);
329 y = x->parent->parent->left;
330 if(y && y->color == RBL_RED)
332 x->parent->color = RBL_BLACK;
333 y->color = RBL_BLACK;
334 x->parent->parent->color = RBL_RED;
335 x = x->parent->parent;
339 if(x == x->parent->left)
344 x->parent->color = RBL_BLACK;
345 x->parent->parent->color = RBL_RED;
346 rbl_left_rotate(x->parent->parent);
351 tree->top->color = RBL_BLACK;
355 /* Create a new node and insert it into the tree */
356 rbl_t *rbl_insert(rbltree_t *tree, void *data)
363 if(rbl_insert_rbl(tree, rbl) == rbl)
372 /* Restore red-black property after violation due to a deletion */
373 void rbl_delete_fixup(rbl_t *x)
377 while(x != x->tree->top && x->color == RBL_BLACK)
379 if(x == x->parent->left)
381 w = x->parent->right;
382 if(w->color == RBL_RED)
384 w->color = RBL_BLACK;
385 x->parent->color = RBL_RED;
386 rbl_left_rotate(x->parent);
387 w = x->parent->right;
389 if(w->left->color == RBL_BLACK && w->right->color == RBL_BLACK)
396 if(w->right->color == RBL_BLACK)
398 w->left->color = RBL_BLACK;
401 w = x->parent->right;
403 w->color = x->parent->color;
404 x->parent->color = RBL_BLACK;
405 w->right->color = RBL_BLACK;
406 rbl_left_rotate(x->parent);
413 if(w->color == RBL_RED)
415 w->color = RBL_BLACK;
416 x->parent->color = RBL_RED;
417 rbl_right_rotate(x->parent);
420 if(w->right->color == RBL_BLACK && w->left->color == RBL_BLACK)
427 if(w->left->color == RBL_BLACK)
429 w->right->color = RBL_BLACK;
434 w->color = x->parent->color;
435 x->parent->color = RBL_BLACK;
436 w->left->color = RBL_BLACK;
437 rbl_right_rotate(x->parent);
443 x->color = RBL_BLACK;
446 /* Unlink node from the tree, but keep the node intact. */
447 rbl_t *rbl_unlink_rbl(rbl_t *rbl)
451 /* Binary tree delete */
453 if(rbl->left && rbl->right)
464 x->parent = y->parent;
469 if(y == y->parent->left)
472 y->parent->right = x;
477 y->right = rbl->right;
478 y->parent = rbl->parent;
479 if(rbl == rbl->parent->left)
480 rbl->parent->left = y;
482 rbl->parent->right = y;
485 /* Linked list delete */
488 rbl->prev->next = rbl->next;
490 rbl->tree->head = rbl->next;
493 rbl->next->prev = rbl->prev;
495 rbl->tree->tail = rbl->prev;
497 /* Red-black part of delete */
499 if(y->color == RBL_BLACK && x)
505 /* Search node in tree and unlink it */
506 rbl_t *rbl_unlink(rbltree_t *tree, void *data)
510 rbl = rbl_search_rbl(tree, data);
518 /* Unlink node and free it */
519 void rbl_delete_rbl(rbl_t *rbl)
525 /* Search node in tree, unlink and free it */
526 void rbl_delete(rbltree_t *tree, void *data)
530 rbl = rbl_unlink(tree, data);
536 /* Optimized unlinking for a complete tree */
537 void rbl_unlink_rbltree(rbltree_t *tree)
541 for(rbl = tree->head; rbl; rbl = next)
557 /* Optimized deletion for a complete tree */
558 void rbl_delete_rbltree(rbltree_t *tree)
562 for(rbl = tree->head; rbl; rbl = next)
573 /* Do action for each list entry (in order)
574 Deletion of entry for which action is called is allowed.
576 void rbl_foreach(rbltree_t *tree, rbl_action_t action)
580 for(rbl = tree->head; rbl; rbl = next)
587 void rbl_foreach_rbl(rbltree_t *tree, rbl_action_rbl_t action)
591 for(rbl = tree->head; rbl; rbl = next)