LibSWOC++ 1.5.14
Solid Wall of C++
Loading...
Searching...
No Matches
RBTree.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright Apache Software Foundation 2019
7
8#include "swoc/RBTree.h"
9
10#include <iostream>
11
12namespace swoc { inline namespace SWOC_VERSION_NS { namespace detail {
13// These equality operators are only used in this file.
14
18inline bool
20 return c == (n ? n->color() : RBNode::Color::BLACK);
21}
22
26inline bool
28 return n == c;
29}
30
31RBNode *
33 return d == Direction::RIGHT ? _right : d == Direction::LEFT ? _left : nullptr;
34}
35
36RBNode *
38 self_type *parent = _parent; // Cache because it can change before we use it.
39 Direction child_dir = _parent ? _parent->direction_of(this) : Direction::NONE;
40 Direction other_dir = this->flip(dir);
41 self_type *child = this;
42
43 if (dir != Direction::NONE && this->child_at(other_dir)) {
44 child = this->child_at(other_dir);
45 this->clear_child(other_dir);
46 this->set_child(child->child_at(dir), other_dir);
47 child->clear_child(dir);
48 child->set_child(this, dir);
49 child->structure_fixup();
50 this->structure_fixup();
51 if (parent) {
52 parent->clear_child(child_dir);
53 parent->set_child(child, child_dir);
54 } else {
55 child->_parent = nullptr;
56 }
57 }
58 return child;
59}
60
61RBNode *
63 if (child) {
64 child->_parent = this;
65 }
66 if (dir == Direction::RIGHT) {
67 _right = child;
68 } else if (dir == Direction::LEFT) {
69 _left = child;
70 }
71 return child;
72}
73
74RBNode *
76 self_type *root = this; // last node seen, root node at the end
77 self_type *p = this;
78 while (p) {
79 p->structure_fixup();
80 root = p;
81 p = root->_parent;
82 }
83 return root;
84}
85
86void
88 n->_color = _color;
89 if (_parent) {
90 Direction d = _parent->direction_of(this);
91 _parent->set_child(nullptr, d);
92 if (_parent != n) {
93 _parent->set_child(n, d);
94 }
95 } else {
96 n->_parent = nullptr;
97 }
98 n->_left = n->_right = nullptr;
99 if (_left && _left != n) {
100 n->set_child(_left, Direction::LEFT);
101 }
102 if (_right && _right != n) {
103 n->set_child(_right, Direction::RIGHT);
104 }
105 _left = _right = nullptr;
106}
107
108/* Rebalance the tree. This node is the unbalanced node. */
109RBNode *
111 self_type *x(this); // the node with the imbalance
112
113 while (x && x->_parent == Color::RED) {
114 Direction child_dir = Direction::NONE;
115
116 if (x->_parent->_parent) {
117 child_dir = x->_parent->_parent->direction_of(x->_parent);
118 } else {
119 break;
120 }
121 Direction other_dir(flip(child_dir));
122
123 self_type *y = x->_parent->_parent->child_at(other_dir);
124 if (y == Color::RED) {
125 x->_parent->_color = Color::BLACK;
126 y->_color = Color::BLACK;
127 x = x->_parent->_parent;
128 x->_color = Color::RED;
129 } else {
130 if (x->_parent->child_at(other_dir) == x) {
131 x = x->_parent;
132 x->rotate(child_dir);
133 }
134 // Note setting the parent color to BLACK causes the loop to exit.
135 x->_parent->_color = Color::BLACK;
136 x->_parent->_parent->_color = Color::RED;
137 x->_parent->_parent->rotate(other_dir);
138 }
139 }
140
141 // every node above this one has a subtree structure change,
142 // so notify it. serendipitously, this makes it easy to return
143 // the new root node.
144 self_type *root = this->ripple_structure_fixup();
145 root->_color = Color::BLACK;
146
147 return root;
148}
149
150// Returns new root node
151RBNode *
153 self_type *root = nullptr; // new root node, returned to caller
154
155 /* Handle two special cases first.
156 - This is the only node in the tree, return a new root of NIL
157 - This is the root node with only one child, return that child as new root
158 */
159 if (!_parent && !(_left && _right)) {
160 if (_left) {
161 _left->_parent = nullptr;
162 root = _left;
163 root->_color = Color::BLACK;
164 } else if (_right) {
165 _right->_parent = nullptr;
166 root = _right;
167 root->_color = Color::BLACK;
168 } // else that was the only node, so leave @a root @c NULL.
169 return root;
170 }
171
172 /* The node to be removed from the tree.
173 If @c this (the target node) has both children, we remove its successor, which cannot have a
174 left child and put that node in place of the target node. Otherwise this node has at most
175 one child, so we can remove it. Note that the successor of a node with a right child is
176 always a right descendant of the node. Therefore, remove_node is an element of the tree
177 rooted at this node. Because of the initial special case checks, we know that remove_node is
178 @b not the root node.
179 */
180 self_type *remove_node(_left && _right ? _right->left_most_descendant() : this);
181
182 // This is the color of the node physically removed from the tree.
183 // Normally this is the color of @a remove_node
184 Color remove_color = remove_node->_color;
185 // Need to remember the direction from @a remove_node to @a splice_node
186 Direction d(Direction::NONE);
187
188 // The child node that will be promoted to replace the removed node.
189 // The choice of left or right is irrelevant, as remove_node has at
190 // most one child (and splice_node may be NIL if remove_node has no
191 // children).
192 self_type *splice_node(remove_node->_left ? remove_node->_left : remove_node->_right);
193
194 if (splice_node) {
195 // @c replace_with copies color so in this case the actual color
196 // lost is that of the splice_node.
197 remove_color = splice_node->_color;
198 remove_node->replace_with(splice_node);
199 } else {
200 // No children on remove node so we can just clip it off the tree
201 // We update splice_node to maintain the invariant that it is
202 // the node where the physical removal occurred.
203 splice_node = remove_node->_parent;
204 // Keep @a d up to date.
205 d = splice_node->direction_of(remove_node);
206 splice_node->set_child(nullptr, d);
207 }
208
209 // If the node to pull out of the tree isn't this one,
210 // then replace this node in the tree with that removed
211 // node in liu of copying the data over.
212 if (remove_node != this) {
213 // Don't leave @a splice_node referring to a removed node
214 if (splice_node == this) {
215 splice_node = remove_node;
216 }
217 this->replace_with(remove_node);
218 }
219
220 root = splice_node->rebalance_after_remove(remove_color, d);
221 root->_color = Color::BLACK;
222 return root;
223}
224
230RBNode *
232 Direction d
233) {
234 self_type *root = nullptr;
235
236 if (Color::BLACK == c) { // only rebalance if too much black
237 self_type *n = this;
238 self_type *parent = n->_parent;
239
240 // If @a direction is set, then we need to start at a leaf pseudo-node.
241 // This is why we need @a parent, otherwise we could just use @a n.
242 if (Direction::NONE != d) {
243 parent = n;
244 n = nullptr;
245 }
246
247 while (parent) { // @a n is not the root
248 // If the current node is Color::RED, we can just recolor and be done
249 if (n && n == Color::RED) {
250 n->_color = Color::BLACK;
251 break;
252 } else {
253 // Parameterizing the rebalance logic on the directions. We
254 // write for the left child case and flip directions for the
255 // right child case
256 Direction near(Direction::LEFT), far(Direction::RIGHT);
257 if ((Direction::NONE == d && parent->direction_of(n) == Direction::RIGHT) || Direction::RIGHT == d) {
258 near = Direction::RIGHT;
259 far = Direction::LEFT;
260 }
261
262 self_type *w = parent->child_at(far); // sibling(n)
263
264 if (w->_color == Color::RED) {
265 w->_color = Color::BLACK;
266 parent->_color = Color::RED;
267 parent->rotate(near);
268 w = parent->child_at(far);
269 }
270
271 self_type *wfc = w->child_at(far);
272 if (w->child_at(near) == Color::BLACK && wfc == Color::BLACK) {
273 w->_color = Color::RED;
274 n = parent;
275 parent = n->_parent;
276 d = Direction::NONE; // Cancel any leaf node logic
277 } else {
278 if (wfc == Color::BLACK) {
279 w->child_at(near)->_color = Color::BLACK;
280 w->_color = Color::RED;
281 w->rotate(far);
282 w = parent->child_at(far);
283 wfc = w->child_at(far); // w changed, update far child cache.
284 }
285 w->_color = parent->_color;
286 parent->_color = Color::BLACK;
287 wfc->_color = Color::BLACK;
288 parent->rotate(near);
289 break;
290 }
291 }
292 }
293 }
294 root = this->ripple_structure_fixup();
295 return root;
296}
297
298RBNode *
300{
301 if (!head || n <= 0)
302 {
303 return head;
304 }
305 RBNode* root = buildTree(head, n, true);
306
307 // The root node is always black.
308 root->_color = Color::BLACK;
309
310 return root;
311}
312
313RBNode *
314RBNode::buildTree(RBNode*& head, int n, bool isBlack)
315{
316 if (n <= 1)
317 {
318 RBNode* currNode = head;
319 currNode->_color = isBlack ? Color::BLACK : Color::RED;
320 head = head->_next;
321 currNode->structure_fixup();
322 return currNode;
323 }
324
325 // Always handle the even number of nodes first because it is guaranteed to contain an n == 2 case.
326 int left_n = n / 2;
327 int right_n = n - left_n - 1;
328 if (right_n % 2 == 0)
329 {
330 std::swap(left_n, right_n);
331 }
332
333 // Recursively construct the left subtree.
334 RBNode* leftBranch = buildTree(head, left_n, !isBlack);
335
336 // Assign the left branch to the current node (head).
337 RBNode* currNode = head;
338 currNode->_left = leftBranch;
339
340 // This can be nullptr if we are at the end.
341 head = head->_next;
342
343 // If this is currently processing 2 nodes, then don't make a right branch
344 // because the left branch has already been made.
345 // No need to check for head == nullptr here because n > 2 inside the block.
346 if (n != 2)
347 {
348 // Recursively construct the right subtree.
349 currNode->_right = buildTree(head, right_n, leftBranch->_color == Color::BLACK);
350 }
351 // If you have an n == 2 case, there is only a left child and it must be red.
352 else
353 {
354 currNode->_left->_color = Color::RED;
355 currNode->_color = Color::BLACK;
356 }
357
358 // If either child is red, then the current node must be black.
359 if (currNode->_left->_color == Color::RED || currNode->_right->_color == Color::RED)
360 {
361 currNode->_color = Color::BLACK;
362 }
363
364 // structure_fixup() needs to be called from the leaf nodes upward.
365 currNode->structure_fixup();
366
367 return currNode;
368}
369
370void
371RBNode::printTree(RBNode* root, std::string indent, bool last)
372{
373 if (root == nullptr) {
374 return;
375 }
376 std::cout << indent;
377 if (last) {
378 std::cout << "└─";
379 indent += " ";
380 } else {
381 std::cout << "├─";
382 indent += "| ";
383 }
384
385 std::string color = (root->_color == Color::RED) ? "R" : "B";
386 std::cout << color << std::endl;
387
388 last = root->_right == nullptr;
389 printTree(root->_left, indent, last);
390 printTree(root->_right, indent, true);
391}
392
397int
399#if BUILD_TESTING
400 int black_ht = 0;
401 int black_ht1, black_ht2;
402
403 if (_left) {
404 black_ht1 = _left->validate();
405 }
406 else
407 black_ht1 = 1;
408
409 if (black_ht1 > 0 && _right)
410 black_ht2 = _right->validate();
411 else
412 black_ht2 = 1;
413
414 if (black_ht1 == black_ht2) {
415 black_ht = black_ht1;
416 if (this->_color == Color::BLACK)
417 ++black_ht;
418 else { // No red-red
419 if (_left == Color::RED)
420 black_ht = 0;
421 else if (_right == Color::RED)
422 black_ht = 0;
423 if (black_ht == 0)
424 std::cout << "Red-red child\n";
425 }
426 } else {
427 std::cout << "Height mismatch " << black_ht1 << " " << black_ht2 << "\n";
428 }
429 if (black_ht > 0 && !this->structure_validate())
430 black_ht = 0;
431
432 return black_ht;
433#else
434 return 0;
435#endif
436}
437
438auto
440 const self_type *n = this;
441 while (n->_left) {
442 n = n->_left;
443 }
444
445 return const_cast<self_type *>(n);
446}
447
448}}} // namespace swoc::SWOC_VERSION_NS::detail
bool operator==(RBNode *n, RBNode::Color c)
Definition RBTree.cc:19
For template deduction guides.
Definition ArenaWriter.cc:9
void clear_child(Direction dir)
Definition RBTree.h:245
virtual void structure_fixup()
Definition RBTree.h:132
static void printTree(self_type *root, std::string indent="", bool last=true)
Recursively print the tree in a human-readable format.
Definition RBTree.cc:371
RBNode()=default
Default constructor.
self_type * rebalance_after_insert()
Rebalance the tree starting at this node.
Definition RBTree.cc:110
Direction direction_of(self_type *const &n) const
Definition RBTree.h:230
self_type * left_most_descendant() const
Definition RBTree.cc:439
self_type * child_at(Direction d) const
Definition RBTree.cc:32
Color _color
node color
Definition RBTree.h:205
self_type * rotate(Direction dir)
Definition RBTree.cc:37
Direction
Directional constants.
Definition RBTree.h:36
static self_type * buildTree(self_type *&head, int n)
Recursively build a balanced RB tree from a sorted linked list.
Definition RBTree.cc:299
self_type * rebalance_after_remove(Color c, Direction dir)
Definition RBTree.cc:231
void replace_with(self_type *n)
Definition RBTree.cc:87
RBNode self_type
self reference type
Definition RBTree.h:27
self_type * remove()
Definition RBTree.cc:152
self_type * set_child(self_type *child, Direction dir)
Definition RBTree.cc:62
Direction flip(Direction d)
Definition RBTree.h:240
self_type * ripple_structure_fixup()
Definition RBTree.cc:75
Color
Node colors.
Definition RBTree.h:30
Color color() const
Definition RBTree.h:235
virtual bool structure_validate()
Definition RBTree.h:253
self_type * _right
right child
Definition RBTree.h:208
self_type * _parent
parent node (needed for rotations)
Definition RBTree.h:206
self_type * _left
left child
Definition RBTree.h:207
self_type * _next
Next node.
Definition RBTree.h:209