Lely core libraries 1.9.2
rbtree.c
Go to the documentation of this file.
1
24#include "util.h"
25#define LELY_UTIL_RBTREE_INLINE extern inline
26#include <lely/util/rbtree.h>
27
28#include <assert.h>
29
31static inline struct rbnode *rbnode_get_parent(const struct rbnode *node);
32
37static void rbnode_set_parent(struct rbnode *node, const struct rbnode *parent);
38
40static inline int rbnode_get_color(const struct rbnode *node);
41
46static inline void rbnode_set_color(struct rbnode *node, int color);
47
49static struct rbnode *rbnode_min(struct rbnode *node);
50
52static struct rbnode *rbnode_max(struct rbnode *node);
53
58static void rbtree_rol(struct rbtree *tree, struct rbnode *node);
59
64static void rbtree_ror(struct rbtree *tree, struct rbnode *node);
65
70static void rbtree_replace(struct rbtree *tree, struct rbnode *old_node,
71 struct rbnode *new_node);
72
73struct rbnode *
74rbnode_prev(const struct rbnode *node)
75{
76 assert(node);
77
78 // If the node has a left subtree, find its rightmost descendant.
79 if (node->left)
80 return rbnode_max(node->left);
81 // Find the lowest ancestor that has the node in its right subtree.
82 struct rbnode *parent = rbnode_get_parent(node);
83 while (parent && node == parent->left) {
84 node = parent;
86 }
87 return parent;
88}
89
90struct rbnode *
91rbnode_next(const struct rbnode *node)
92{
93 assert(node);
94
95 // If the node has a right subtree, find its leftmost descendant.
96 if (node->right)
97 return rbnode_min(node->right);
98 // Find the lowest ancestor that has the node in its left subtree.
99 struct rbnode *parent = rbnode_get_parent(node);
100 while (parent && node == parent->right) {
101 node = parent;
103 }
104 return parent;
105}
106
107void
108rbtree_insert(struct rbtree *tree, struct rbnode *node)
109{
110 assert(tree);
111 assert(tree->cmp);
112 assert(node);
113
114 // Find the parent of the new node.
115 struct rbnode *parent = NULL;
116 struct rbnode *next = tree->root;
117 while (next) {
118 parent = next;
119 // clang-format off
120 next = tree->cmp(node->key, next->key) < 0
121 ? next->left : next->right;
122 // clang-format on
123 }
124 // Attach the node to its parent.
125 if (!parent)
126 tree->root = node;
127 else if (tree->cmp(node->key, parent->key) < 0)
128 parent->left = node;
129 else
130 parent->right = node;
131 // Initialize the node.
133 rbnode_set_color(node, 1);
134 node->left = NULL;
135 node->right = NULL;
136 // Fix violations of the red-black properties.
137 while (rbnode_get_color(parent)) {
138 struct rbnode *gparent = rbnode_get_parent(parent);
139 if (parent == gparent->left) {
140 if (rbnode_get_color(gparent->right)) {
141 // Case 1: flip colors.
142 rbnode_set_color(gparent, 1);
144 rbnode_set_color(gparent->right, 0);
145 node = gparent;
146 } else {
147 if (node == parent->right) {
148 // Case 2: left rotate at grandparent.
149 node = parent;
150 rbtree_rol(tree, node);
152 gparent = rbnode_get_parent(parent);
153 }
154 // Case 3: right rotate at grandparent.
155 rbnode_set_color(gparent, 1);
157 rbtree_ror(tree, gparent);
158 }
159 } else {
160 if (rbnode_get_color(gparent->left)) {
161 // Case 1: flip colors.
162 rbnode_set_color(gparent, 1);
164 rbnode_set_color(gparent->left, 0);
165 node = gparent;
166 } else {
167 if (node == parent->left) {
168 // Case 2: right rotate at grandparent.
169 node = parent;
170 rbtree_ror(tree, node);
172 gparent = rbnode_get_parent(parent);
173 }
174 // Case 3: left rotate at grandparent.
175 rbnode_set_color(gparent, 1);
177 rbtree_rol(tree, gparent);
178 }
179 }
181 }
182 rbnode_set_color(tree->root, 0);
183
184 tree->num_nodes++;
185}
186
187void
188rbtree_remove(struct rbtree *tree, struct rbnode *node)
189{
190 assert(tree);
191 assert(node);
192
193 int color = rbnode_get_color(node);
194 struct rbnode *parent = rbnode_get_parent(node);
195 // Remove the node from the tree. After removal, node points to the
196 // subtree in which we might have introduced red-black property
197 // violations.
198 if (!node->left) {
199 // There is no left subtree, so we can replace the node by its
200 // right subtree.
201 rbtree_replace(tree, node, node->right);
202 node = node->right;
203 } else if (!node->right) {
204 // There is no right subtree, so we can replace the node by its
205 // left subtree.
206 rbtree_replace(tree, node, node->left);
207 node = node->left;
208 } else {
209 // There is both a left and a right subtree, so we replace the
210 // node by its successor. First, find the successor and give it
211 // the same color as the node to be removed.
212 struct rbnode *next = rbnode_min(node->right);
213 color = rbnode_get_color(next);
215 struct rbnode *tmp = next->right;
216 if (rbnode_get_parent(next) == node) {
217 parent = next;
218 } else {
220 // If the successor is not a child of the node to be
221 // removed, we remove it from its parent.
222 rbtree_replace(tree, next, next->right);
223 next->right = node->right;
224 rbnode_set_parent(next->right, next);
225 }
226 // Replace the node to be removed by its successor.
227 rbtree_replace(tree, node, next);
228 // The successor has no left subtree (by definition). Attach the
229 // left subtree of the node to be removed to the successor.
230 next->left = node->left;
231 rbnode_set_parent(next->left, next);
232 node = tmp;
233 }
234 // Fix violations of the red-black properties. This can only occur if
235 // the removed node (or its successor) was black.
236 if (color)
237 return;
238 while (node != tree->root && !rbnode_get_color(node)) {
239 if (node == parent->left) {
240 struct rbnode *tmp = parent->right;
241 if (rbnode_get_color(tmp)) {
242 // Case 1: left rotate at parent.
244 rbnode_set_color(tmp, 0);
245 rbtree_rol(tree, parent);
246 tmp = parent->right;
247 }
248 if (!rbnode_get_color(tmp->left)
249 && !rbnode_get_color(tmp->right)) {
250 // Case 2: color flip at sibling.
251 rbnode_set_color(tmp, 1);
252 node = parent;
254 } else {
255 if (!rbnode_get_color(tmp->right)) {
256 // Case 3: right rotate at sibling.
257 rbnode_set_color(tmp, 1);
258 rbnode_set_color(tmp->left, 0);
259 rbtree_ror(tree, tmp);
260 tmp = parent->right;
261 }
262 // Case 4: left rotate at parent and color flip.
265 rbnode_set_color(tmp->right, 0);
266 rbtree_rol(tree, parent);
267 node = tree->root;
268 }
269 } else {
270 struct rbnode *tmp = parent->left;
271 if (rbnode_get_color(tmp)) {
272 // Case 1: right rotate at parent.
274 rbnode_set_color(tmp, 0);
275 rbtree_ror(tree, parent);
276 tmp = parent->left;
277 }
278 if (!rbnode_get_color(tmp->right)
279 && !rbnode_get_color(tmp->left)) {
280 // Case 2: color flip at sibling.
281 rbnode_set_color(tmp, 1);
282 node = parent;
284 } else {
285 if (!rbnode_get_color(tmp->left)) {
286 // Case 3: left rotate at sibling.
287 rbnode_set_color(tmp, 1);
288 rbnode_set_color(tmp->right, 0);
289 rbtree_rol(tree, tmp);
290 tmp = parent->left;
291 }
292 // Case 4: right rotate at parent and color
293 // flip.
296 rbnode_set_color(tmp->left, 0);
297 rbtree_ror(tree, parent);
298 node = tree->root;
299 }
300 }
301 }
302 rbnode_set_color(node, 0);
303
304 tree->num_nodes--;
305}
306
307struct rbnode *
308rbtree_find(const struct rbtree *tree, const void *key)
309{
310 assert(tree);
311 assert(tree->cmp);
312
313 struct rbnode *node = tree->root;
314 while (node) {
315 int cmp = tree->cmp(key, node->key);
316 if (!cmp)
317 break;
318 node = cmp < 0 ? node->left : node->right;
319 }
320 return node;
321}
322
323struct rbnode *
324rbtree_first(const struct rbtree *tree)
325{
326 assert(tree);
327
328 return tree->root ? rbnode_min(tree->root) : NULL;
329}
330
331struct rbnode *
332rbtree_last(const struct rbtree *tree)
333{
334 assert(tree);
335
336 return tree->root ? rbnode_max(tree->root) : NULL;
337}
338
339static inline struct rbnode *
340rbnode_get_parent(const struct rbnode *node)
341{
342 return node ? (struct rbnode *)(node->parent & ~(uintptr_t)1) : NULL;
343}
344
345static void
346rbnode_set_parent(struct rbnode *node, const struct rbnode *parent)
347{
348 if (!node)
349 return;
350
351 node->parent = (uintptr_t)parent | rbnode_get_color(node);
352}
353
354static inline int
355rbnode_get_color(const struct rbnode *node)
356{
357 return node ? node->parent & (uintptr_t)1 : 0;
358}
359
360static inline void
361rbnode_set_color(struct rbnode *node, int color)
362{
363 if (!node)
364 return;
365
366 if (color)
367 node->parent |= (uintptr_t)1;
368 else
369 node->parent &= ~(uintptr_t)1;
370}
371
372static struct rbnode *
373rbnode_min(struct rbnode *node)
374{
375 assert(node);
376
377 while (node->left)
378 node = node->left;
379 return node;
380}
381
382static struct rbnode *
383rbnode_max(struct rbnode *node)
384{
385 assert(node);
386
387 while (node->right)
388 node = node->right;
389 return node;
390}
391
392static void
393rbtree_rol(struct rbtree *tree, struct rbnode *node)
394{
395 assert(tree);
396 assert(node);
397 assert(node->right);
398
399 struct rbnode *tmp = node->right;
400 node->right = tmp->left;
401 rbnode_set_parent(tmp->left, node);
402 tmp->left = node;
403 struct rbnode *parent = rbnode_get_parent(node);
404 rbnode_set_parent(node, tmp);
406 if (!parent)
407 tree->root = tmp;
408 else if (node == parent->left)
409 parent->left = tmp;
410 else
411 parent->right = tmp;
412}
413
414static void
415rbtree_ror(struct rbtree *tree, struct rbnode *node)
416{
417 assert(tree);
418 assert(node);
419 assert(node->left);
420
421 struct rbnode *tmp = node->left;
422 node->left = tmp->right;
423 rbnode_set_parent(tmp->right, node);
424 tmp->right = node;
425 struct rbnode *parent = rbnode_get_parent(node);
426 rbnode_set_parent(node, tmp);
428 if (!parent)
429 tree->root = tmp;
430 else if (node == parent->right)
431 parent->right = tmp;
432 else
433 parent->left = tmp;
434}
435
436static void
437rbtree_replace(struct rbtree *tree, struct rbnode *old_node,
438 struct rbnode *new_node)
439{
440 struct rbnode *parent = rbnode_get_parent(old_node);
441 if (!parent)
442 tree->root = new_node;
443 else if (old_node == parent->left)
444 parent->left = new_node;
445 else
446 parent->right = new_node;
447 rbnode_set_parent(new_node, parent);
448}
static struct rbnode * rbnode_max(struct rbnode *node)
Returns the rightmost descendant of node.
Definition: rbtree.c:383
struct rbnode * rbtree_last(const struct rbtree *tree)
Returns a pointer to the last (rightmost) node in a red-black tree.
Definition: rbtree.c:332
void rbtree_insert(struct rbtree *tree, struct rbnode *node)
Inserts a node into a red-black tree.
Definition: rbtree.c:108
struct rbnode * rbtree_find(const struct rbtree *tree, const void *key)
Finds a node in a red-black tree.
Definition: rbtree.c:308
struct rbnode * rbtree_first(const struct rbtree *tree)
Returns a pointer to the first (leftmost) node in a red-black tree.
Definition: rbtree.c:324
static void rbtree_ror(struct rbtree *tree, struct rbnode *node)
Rotates node clockwise (right), i.e., it is replaced in the tree by its left child,...
Definition: rbtree.c:415
static void rbtree_replace(struct rbtree *tree, struct rbnode *old_node, struct rbnode *new_node)
Replaces old_node by new_node in tree by updating its parent.
Definition: rbtree.c:437
static int rbnode_get_color(const struct rbnode *node)
Returns the color of node, or 0 (black) if node is NULL.
Definition: rbtree.c:355
struct rbnode * rbnode_next(const struct rbnode *node)
Returns a pointer to the next (in-order) node in a red-black tree with respect to node.
Definition: rbtree.c:91
static struct rbnode * rbnode_get_parent(const struct rbnode *node)
Returns the parent of node, or NULL if node is NULL.
Definition: rbtree.c:340
static void rbnode_set_color(struct rbnode *node, int color)
Sets the color of node to 0 (black) if color is 0, or to 1 (red) otherwise.
Definition: rbtree.c:361
static void rbtree_rol(struct rbtree *tree, struct rbnode *node)
Rotates node counter-clockwise (left), i.e., it is replaced in the tree by its right child,...
Definition: rbtree.c:393
struct rbnode * rbnode_prev(const struct rbnode *node)
Returns a pointer to the previous (in-order) node in a red-black tree with respect to node.
Definition: rbtree.c:74
static void rbnode_set_parent(struct rbnode *node, const struct rbnode *parent)
Sets the parent of node to parent.
Definition: rbtree.c:346
static struct rbnode * rbnode_min(struct rbnode *node)
Returns the leftmost descendant of node.
Definition: rbtree.c:373
void rbtree_remove(struct rbtree *tree, struct rbnode *node)
Removes a node from a red-black tree.
Definition: rbtree.c:188
This header file is part of the utilities library; it contains the red-black tree declarations.
This is the internal header file of the utilities library.
A node in a red-black tree.
Definition: rbtree.h:52
struct rbnode * left
A pointer to the left child node.
Definition: rbtree.h:65
struct rbnode * right
A pointer to the right child node.
Definition: rbtree.h:67
const void * key
A pointer to the key for this node.
Definition: rbtree.h:58
uintptr_t parent
A pointer to the parent node.
Definition: rbtree.h:63
A red-black tree.
Definition: rbtree.h:90
rbtree_cmp_t * cmp
A pointer to the function used to compare two keys.
Definition: rbtree.h:92
size_t num_nodes
The number of nodes stored in the tree.
Definition: rbtree.h:96
struct rbnode * root
A pointer to the root node of the tree.
Definition: rbtree.h:94