datastructures 0.1.0
Loading...
Searching...
No Matches
_avl.ipp
Go to the documentation of this file.
1
7
8#pragma once
9
10#include "_avl.hpp" // for clangd
11
12#include <format>
13#include <sstream>
14#include <stack>
15#include <string>
16#include <type_traits>
17
18namespace datastructures {
19namespace detail {
20
21// ==== Constructors & Assigments ====
22
23template <class TKey, class TItem, class TKeyComp, class TAlloc>
25 const typename base::comparator_type &comparator,
26 const typename base::allocator_type &allocator)
27 : base(comparator, allocator) {}
28
29template <class TKey, class TItem, class TKeyComp, class TAlloc>
31 : base(other.comparator, other.allocator) {
32 clone_tree(other);
33}
34
35template <class TKey, class TItem, class TKeyComp, class TAlloc>
38 this->comparator = other.comparator;
39 this->allocator = other.allocator;
40
41 clone_tree(other);
42
43 return *this;
44}
45
46template <class TKey, class TItem, class TKeyComp, class TAlloc>
48 : base(std::move(other.comparator), std::move(other.allocator)) {
49 root = other.root;
50 this->node_count = other.node_count;
51
52 other.root = nullptr;
53 other.node_count = 0;
54}
55
56template <class TKey, class TItem, class TKeyComp, class TAlloc>
59 this->comparator = std::move(other.comparator);
60 this->allocator = std::move(other.allocator);
61
62 root = other.root;
63 this->node_count = other.node_count;
64
65 other.root = nullptr;
66 other.node_count = 0;
67
68 return *this;
69}
70
71template <class TKey, class TItem, class TKeyComp, class TAlloc>
75
76// ==== Helper Functions ====
77
78template <class TKey, class TItem, class TKeyComp, class TAlloc>
80 const avl_tree &other) {
81 this->node_count = other.node_count;
82
83 root = this->create_node(other.root->item);
84 root->sign = other.root->sign;
85
86 std::stack<std::pair<node_ptr, node_ptr>> stack;
87
88 stack.push(std::make_pair(root, other.root));
89
90 while (!stack.empty()) {
91 auto [node, other_node] = stack.top();
92 stack.pop();
93
94 if (other_node->left != nullptr) {
95 node->left = this->create_node(other_node->left->item);
96 node->left->parent = node;
97 node->left->sign = other_node->left->sign;
98
99 stack.push(std::make_pair(node->left, other_node->left));
100 }
101
102 if (other_node->right != nullptr) {
103 node->right = this->create_node(other_node->right->item);
104 node->right->parent = node;
105 node->right->sign = other_node->right->sign;
106
107 stack.push(std::make_pair(node->right, other_node->right));
108 }
109 }
110}
111
112template <class TKey, class TItem, class TKeyComp, class TAlloc>
113void avl_tree<TKey, TItem, TKeyComp, TAlloc>::rotate(node_ptr x) noexcept {
114 node_ptr y = x->parent;
115 node_ptr p = y->parent;
116
117 // update the parent of the x,y pair
118 if (p != nullptr) {
119 if (p->left == y) {
120 p->left = x;
121 }
122 else {
123 p->right = x;
124 }
125 }
126
127 if (y == root) {
128 root = x;
129 }
130
131 // swap x and y
132 node_ptr b;
133
134 if (y->left == x) {
135 b = x->right;
136 y->left = b;
137 x->right = y;
138 }
139 else {
140 b = x->left;
141 y->right = b;
142 x->left = y;
144
145 // update parents
146 x->parent = p;
147 y->parent = x;
148
149 if (b != nullptr) {
150 b->parent = y;
151 }
152}
154// ==== Access Operations ====
155
156template <class TKey, class TItem, class TKeyComp, class TAlloc>
159 const key_type &key) const noexcept {
160 node_ptr node = root;
161
162 while (true) {
163 if (node == nullptr) {
164 return nullptr;
165 }
166 if (this->comparator(key, node->item)) {
167 node = node->left;
168 }
169 else if (this->comparator(node->item, key)) {
170 node = node->right;
171 }
172 else {
173 return node;
174 }
175 }
176}
177
178template <class TKey, class TItem, class TKeyComp, class TAlloc>
181 node_ptr node) const noexcept {
182 if (node == nullptr) {
183 return nullptr;
184 }
185
186 if (node->right == nullptr) {
187 while (node->parent != nullptr) {
188 if (!is_right_child(node)) {
189 return node->parent;
190 }
191 node = node->parent;
192 }
193 return nullptr;
194 }
195
196 return this->min_from(node->right);
197}
198
199template <class TKey, class TItem, class TKeyComp, class TAlloc>
202 node_ptr node) const noexcept {
203 if (node == nullptr) {
204 return nullptr;
205 }
206
207 if (node->left == nullptr) {
208 while (node->parent != nullptr) {
209 if (is_right_child(node)) {
210 return node->parent;
211 }
212 node = node->parent;
213 }
214 return nullptr;
215 }
216
217 return this->max_from(node->left);
218}
219
220template <class TKey, class TItem, class TKeyComp, class TAlloc>
221template <bool lower>
224 const key_type &key) const noexcept {
225 if (root == nullptr) {
226 return nullptr;
227 }
228
229 node_ptr node = root;
230
231 while (true) {
232 if (this->comparator(key, node->item)) {
233 if (node->left == nullptr) {
234 return node;
235 }
236 node = node->left;
237 }
238 else if (this->comparator(node->item, key)) {
239 if (node->right == nullptr) {
240 return successor(node);
241 }
242 node = node->right;
243 }
244 else {
245 if constexpr (lower) {
246 return node;
247 }
248 else {
249 return successor(node);
250 }
251 }
252 }
253}
254
255// ==== Update Operations ====
256
257template <class TKey, class TItem, class TKeyComp, class TAlloc>
259 node_ptr node = root;
260
261 while (node != nullptr) {
262 if (node->left != nullptr) {
263 node_ptr tmp = node->left;
264 node->left = tmp->right;
265 tmp->right = node;
266 node = tmp;
267 }
268 else {
269 node_ptr tmp = node->right;
270 this->destroy_node(node);
271 node = tmp;
272 }
273 }
274
275 root = nullptr;
276 this->node_count = 0;
277}
278
279template <class TKey, class TItem, class TKeyComp, class TAlloc>
280template <class TInsertCallback, class TAssignCallback>
281std::pair<typename avl_tree<TKey, TItem, TKeyComp, TAlloc>::node_ptr, bool>
283 const key_type &key, TInsertCallback &&insert_callback,
284 TAssignCallback &&assign_callback) {
285 if (root == nullptr) {
286 root =
287 this->create_node(std::forward<TInsertCallback>(insert_callback));
288 ++this->node_count;
289 return std::make_pair(root, true);
290 }
291
292 node_ptr node = root;
293
294 node_ptr new_node = nullptr;
295
296 while (true) {
297 if (this->comparator(key, node->item)) {
298 if (node->left == nullptr) {
299 new_node = this->create_node(
300 std::forward<TInsertCallback>(insert_callback));
301
302 node->left = new_node;
303 node->left->parent = node;
304 ++this->node_count;
305
306 node = node->left;
307 break; // propagate height change
308 }
309 node = node->left;
310 }
311 else if (this->comparator(node->item, key)) {
312 if (node->right == nullptr) {
313 new_node = this->create_node(
314 std::forward<TInsertCallback>(insert_callback));
315
316 node->right = new_node;
317 node->right->parent = node;
318 ++this->node_count;
319
320 node = node->right;
321 break; // propagate height change
322 }
323 node = node->right;
324 }
325 else {
326 assign_callback(node->item);
327 return std::make_pair(node, false);
328 }
329 }
330
331 // height changed
332
333 while (node->parent != nullptr) {
334 node_ptr parent = node->parent;
335
336 const typename base::sign_type positive =
337 (is_right_child(node)) ? +1 : -1;
338
339 if (parent->sign == -positive) {
340 parent->sign = 0;
341 break; // balanced itself
342 }
343
344 if (parent->sign == positive) {
345 // we need to rotate
346
347 if (node->sign == positive) {
348 rotate(node);
349 parent->sign = 0;
350 node->sign = 0;
351 }
352
353 else { // node->sign cannot be 0 here => must be -positive
354 node_ptr child = (positive == 1) ? node->left : node->right;
355 rotate(child);
356 rotate(child);
357
358 // correct the signs for parent, node and child
359 if (child->sign == positive) {
360 node->sign = 0;
361 parent->sign = -positive;
362 }
363 else if (child->sign == -positive) {
364 node->sign = +positive;
365 parent->sign = 0;
366 }
367 else { // child is a new-born
368 node->sign = 0;
369 parent->sign = 0;
370 }
371 child->sign = 0;
372 }
373
374 break; // balanced
375 }
376
377 // parent->sign == 0
378
379 parent->sign = positive;
380 node = parent;
381 }
382
383 return std::make_pair(new_node, true);
384}
385
386template <class TKey, class TItem, class TKeyComp, class TAlloc>
388 node_ptr replacement;
389 node_ptr parent = node->parent;
390
391 bool from_right = false;
392
393 if (parent != nullptr) {
394 from_right = is_right_child(node);
395 // otherwise we wont need this flag
396 }
397
398 // also find and store the location from where to bubble the balancing
399 // events
400
401 node_ptr balance_from_node = parent;
402 bool balance_from_right = from_right;
403
404 if (is_leaf(node)) {
405 replacement = nullptr;
406 }
407 else if (node->left == nullptr) {
408 replacement = node->right;
409
410 // we do not need to worry about the sign of the old node and we can
411 // keep the old `balance_from_node`, since the replacement is always
412 // a leaf, same in the next case
413 }
414 else if (node->right == nullptr) {
415 replacement = node->left;
416 }
417 else {
418 // both children exist
419 replacement = this->min_from(node->right);
420
421 if (replacement->parent != node) {
422 node_ptr par = replacement->parent;
423
424 // we need to balance from down there
425 balance_from_node = replacement->parent;
426 balance_from_right = false;
427
428 par->left = replacement->right;
429
430 // set new parent for the former right child of the new root
431 if (par->left != nullptr) {
432 par->left->parent = par;
433 }
434
435 replacement->right = node->right;
436 replacement->right->parent = replacement;
437 }
438 else {
439 // we actually need to balance from the replacement node itself
440 // because it is now the parent of the deleted space
441 balance_from_node = replacement;
442 balance_from_right = true;
443 }
444
445 // don't forget to update the sign
446 replacement->sign = node->sign;
447
448 replacement->left = node->left;
449 if (replacement->left != nullptr) {
450 replacement->left->parent = replacement;
451 }
452 }
453
454 // Free the node.
455
456 this->destroy_node(node);
457 --this->node_count;
458
459 // Update the deleted node's parent
460
461 if (parent == nullptr) {
462 // the node was root
463 root = replacement;
464 }
465 else if (from_right) {
466 parent->right = replacement;
467 }
468 else {
469 parent->left = replacement;
470 }
471
472 if (replacement != nullptr) {
473 replacement->parent = parent;
474 }
475
476 // balance
477
478 if (balance_from_node == nullptr) {
479 return;
480 }
481
482 while (true) {
483 node_ptr next_node = balance_from_node->parent;
484 bool next_from_right = false;
485 if (next_node != nullptr) {
486 next_from_right = is_right_child(balance_from_node);
487 }
488
489 const typename base::sign_type positive = balance_from_right ? +1 : -1;
490
491 if (balance_from_node->sign == 0) {
492 balance_from_node->sign = -positive;
493 // height didn't change
494 return;
495 }
496 else if (balance_from_node->sign == -positive) {
497 // we need to rotate
498
499 node_ptr child = balance_from_right ? balance_from_node->left
500 : balance_from_node->right;
501
502 // child != nullptr, because it's parent's sign is -positive
503
504 if (child->sign == -positive) {
505 rotate(child);
506 child->sign = 0;
507 balance_from_node->sign = 0;
508 // continue propagating
509 }
510 else if (child->sign == 0) {
511 rotate(child);
512 child->sign = positive;
513 balance_from_node->sign = -positive;
514 return;
515 }
516 else { // child->sign == positive
517 node_ptr grand_child =
518 balance_from_right ? child->right : child->left;
519
520 rotate(grand_child);
521 rotate(grand_child);
522
523 if (grand_child->sign == positive) {
524 balance_from_node->sign = 0;
525 child->sign = -positive;
526 }
527 else if (grand_child->sign == -positive) {
528 balance_from_node->sign = positive;
529 child->sign = 0;
530 }
531 else {
532 balance_from_node->sign = 0;
533 child->sign = 0;
534 }
535
536 grand_child->sign = 0;
537
538 // continue propagating
539 }
540 }
541 else { // balance_from_node->sign == positive
542 balance_from_node->sign = 0;
543 // continue propagating
544 }
545
546 if (next_node == nullptr) {
547 return;
548 }
549
550 balance_from_node = next_node;
551 balance_from_right = next_from_right;
552 }
553};
554
555// ==== Size ====
556
557template <class TKey, class TItem, class TKeyComp, class TAlloc>
559 if (root == nullptr) {
560 return -1;
561 }
562
563 int height = 0;
564 std::stack<std::pair<node_ptr, int>> stack;
565 stack.emplace(root, 0);
566
567 while (!stack.empty()) {
568 auto [node, level] = stack.top();
569 stack.pop();
570
571 height = std::max(level, height);
572
573 if (node->left != nullptr) {
574 stack.emplace(node->left, level + 1);
575 }
576
577 if (node->right != nullptr) {
578 stack.emplace(node->right, level + 1);
579 }
580 }
581
582 return height;
583}
584
585// ==== Debug Function ====
586
587template <class TKey, class TItem, class TKeyComp, class TAlloc>
588std::string
590 auto get_repr = [](node_ptr node) -> std::string {
591 if (node == nullptr) {
592 return "NULL";
593 }
594
595 if constexpr (std::is_convertible_v<decltype(node->item),
596 std::string>) {
597 return std::string(node->item);
598 }
599 else if constexpr (requires { std::to_string(node->item); }) {
600 return std::to_string(node->item);
601 }
602 else if constexpr (requires { std::format("{}", node->item); }) {
603 return std::format("{}", node->item);
604 }
605 else {
606 return std::format("{}", static_cast<const void *>(node));
607 }
608 };
609
610 auto get_id = [](node_ptr node) -> std::string {
611 return std::format("{}", static_cast<const void *>(node));
612 };
613
614 std::stringstream ss;
615
616 ss << "digraph {\n";
617
618 std::stack<node_ptr> s;
619 if (root != nullptr) {
620 s.push(root);
621 }
622
623 while (!s.empty()) {
624 node_ptr node = s.top();
625 s.pop();
626
627 std::string sign = "0";
628
629 if (node->sign == +1) {
630 sign = "+1";
631 }
632 else if (node->sign == -1) {
633 sign = "-1";
634 }
635
636 ss << " " << get_id(node) << " [label=\"" << get_repr(node) << "\\n"
637 << sign << "\"";
638
639 if (node == root) {
640 ss << ", style=filled, fillcolor=lightblue";
641 }
642
643 ss << "];\n";
644
645 if (node->left != nullptr) {
646 ss << " " << get_id(node) << " -> " << get_id(node->left)
647 << ";\n";
648 s.push(node->left);
649 }
650 else if (print_invis) {
651 ss << " inv" << get_id(node) << "L [style=invis];\n";
652 ss << " " << get_id(node) << " -> inv" << get_id(node)
653 << "L [style=invis];\n";
654 }
655 if (node->right != nullptr) {
656 ss << " " << get_id(node) << " -> " << get_id(node->right)
657 << ";\n";
658 s.push(node->right);
659 }
660 else if (print_invis) {
661 ss << " inv" << get_id(node) << "R [style=invis];\n";
662 ss << " " << get_id(node) << " -> inv" << get_id(node)
663 << "R [style=invis];\n";
664 }
665 }
666
667 ss << "}\n\n";
668
669 return ss.str();
670}
671
672} // namespace detail
673} // namespace datastructures
Declarations of the ethereal AVL tree.
comparator_type comparator
Definition _avl_common.hpp:105
node_alloc_type allocator
Definition _avl_common.hpp:106
AVL tree implementation.
Definition _avl.hpp:77
typename base::node_ptr node_ptr
Definition _avl.hpp:83
~avl_tree() noexcept
Destroys the tree.
Definition _avl.ipp:72
void clear() noexcept
Erases the whole tree.
Definition _avl.ipp:258
avl_tree(const typename base::comparator_type &comparator, const typename base::allocator_type &allocator)
Constructs new AVL tree.
Definition _avl.ipp:24
node_ptr successor(node_ptr node) const noexcept
Returns the successor to the node.
Definition _avl.ipp:180
std::pair< node_ptr, bool > insert(const key_type &key, TInsertCallback &&insert_callback, TAssignCallback &&assign_callback)
Inserts an item to the tree.
int get_height() const
Returns the current height of the tree.
Definition _avl.ipp:558
std::string to_dot(bool print_invis) const
Returns the dot representation of the tree.
Definition _avl.ipp:589
node_ptr find(const key_type &key) const noexcept
Finds a node with the given key, if there isn't any returns a nullptr.
Definition _avl.ipp:158
void erase(node_ptr node) noexcept
Erases the node.
Definition _avl.ipp:387
node_ptr predecessor(node_ptr node) const noexcept
Returns the predecessor to the node.
Definition _avl.ipp:201
avl_tree & operator=(const avl_tree &other)
Copies another tree.
Definition _avl.ipp:37
node_ptr bound(const key_type &key) const noexcept
A 2-in-1 function for both lower and upper bounds accessing.
Definition _avl.ipp:223
typename base::key_type key_type
Definition _avl.hpp:84
Declarations of the persistent map.
Definition _avl.hpp:14