aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
binSearchTree_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2025 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2025 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40#pragma once
41
42
49
50#include <sstream>
51#include <string>
52
55
56#ifndef DOXYGEN_SHOULD_SKIP_THIS
57
58namespace gum {
59
60 // ===========================================================================
61 // ===========================================================================
62 // === GENERIC BINARY SEARCH TREE ITERATORS ===
63 // ===========================================================================
64 // ===========================================================================
65
66 template < typename Val, class Cmp, class Node >
68 node_(nullptr), next_node_(nullptr), prev_node_(nullptr), parent_(nullptr),
69 left_child_(nullptr), right_child_(nullptr), tree_(nullptr), next_iter_(nullptr) {
70 GUM_CONSTRUCTOR(BinSearchTreeIterator);
71 }
72
73 template < typename Val, class Cmp, class Node >
74 INLINE BinSearchTreeIterator< Val, Cmp, Node >::BinSearchTreeIterator(
76 node_(from.node_), next_node_(from.next_node_), prev_node_(from.prev_node_),
77 parent_(from.parent_), left_child_(from.left_child_), right_child_(from.right_child_),
78 tree_(from.tree_) {
79 GUM_CONS_CPY(BinSearchTreeIterator);
80
81 if (tree_ != nullptr) {
82 next_iter_ = tree_->iterator_list_;
83 tree_->iterator_list_ = this;
84 } else next_iter_ = nullptr;
85 }
86
87 template < typename Val, class Cmp, class Node >
88 INLINE void BinSearchTreeIterator< Val, Cmp, Node >::initialize_(
89 const BinSearchTree< Val, Cmp, Node >* tree,
90 const Node* current_node,
91 bool add_to_iterator_list) {
92 // remember: we do not check here whether the iterator already belongs to
93 // a tree. We assume that it is not so.
94
95 tree_ = const_cast< BinSearchTree< Val, Cmp, Node >* >(tree);
96 node_ = const_cast< Node* >(current_node);
97
98 if (add_to_iterator_list && (tree_ != nullptr)) {
99 next_iter_ = tree_->iterator_list_;
100 tree_->iterator_list_ = this;
101 }
102 }
103
104 template < typename Val, class Cmp, class Node >
105 INLINE void BinSearchTreeIterator< Val, Cmp, Node >::detachFromTree_() {
106 if (tree_ != nullptr) {
107 BinSearchTreeIterator< Val, Cmp, Node >*iter, *prev_iter = nullptr;
108
109 for (iter = tree_->iterator_list_; iter != this && iter != nullptr;
110 prev_iter = iter, iter = iter->next_iter_) {}
111
112 if (iter != nullptr) {
113 if (prev_iter != nullptr) prev_iter->next_iter_ = next_iter_;
114 else tree_->iterator_list_ = next_iter_;
115 }
116 }
117 }
118
119 template < typename Val, class Cmp, class Node >
120 INLINE BinSearchTreeIterator< Val, Cmp, Node >::~BinSearchTreeIterator() {
121 GUM_DESTRUCTOR(BinSearchTreeIterator);
122
123 // remove the iterator from its tree iterator's list
124 detachFromTree_();
125 }
126
127 template < typename Val, class Cmp, class Node >
128 INLINE void BinSearchTreeIterator< Val, Cmp, Node >::clear() {
129 // remove the iterator from its tree iterator's list
130 detachFromTree_();
131
132 // reset the iterator
133 node_ = nullptr;
134 next_node_ = nullptr;
135 prev_node_ = nullptr;
136 parent_ = nullptr;
137 left_child_ = nullptr;
138 right_child_ = nullptr;
139 tree_ = nullptr;
140 next_iter_ = nullptr;
141 }
142
143 template < typename Val, class Cmp, class Node >
145 BinSearchTreeIterator< Val, Cmp, Node >::operator=(
147 // avoid self assignment
148 if (this != &from) {
149 GUM_OP_CPY(BinSearchTreeIterator);
150
151 // if from and this belong to different trees, detach this from its
152 // current tree
153 if (from.tree_ != tree_) {
154 detachFromTree_();
155 tree_ = from.tree_;
156
157 if (tree_ != nullptr) {
158 next_iter_ = tree_->iterator_list_;
159 tree_->iterator_list_ = this;
160 } else next_iter_ = nullptr;
161 }
162
163 // make the iterators point to the same element
164 node_ = from.node_;
165 next_node_ = from.next_node_;
166 prev_node_ = from.prev_node_;
167 parent_ = from.parent_;
168 left_child_ = from.left_child_;
169 right_child_ = from.right_child_;
170 }
171
172 return *this;
173 }
174
175 template < typename Val, class Cmp, class Node >
176 INLINE const Val& BinSearchTreeIterator< Val, Cmp, Node >::operator*() const {
177 if (node_ != nullptr) return node_->value();
178
179 GUM_ERROR(UndefinedIteratorValue, "the iterator does not point to a node of the binary tree")
180 }
181
182 template < typename Val, class Cmp, class Node >
183 INLINE Node* BinSearchTree< Val, Cmp, Node >::minNode_(Node* node) const {
184 Node* prevNode = nullptr;
185
186 for (; node != nullptr; prevNode = node, node = node->leftChild()) {}
187
188 return prevNode;
189 }
190
191 template < typename Val, class Cmp, class Node >
192 INLINE Node* BinSearchTree< Val, Cmp, Node >::maxNode_(Node* node) const {
193 Node* prevNode = nullptr;
194
195 for (; node != nullptr; prevNode = node, node = node->rightChild()) {}
196
197 return prevNode;
198 }
199
200 template < typename Val, class Cmp, class Node >
201 INLINE Node* BinSearchTree< Val, Cmp, Node >::succNode_(Node* node) const {
202 if (node == nullptr) return nullptr;
203
204 if (node->rightChild()) return minNode_(node->rightChild());
205
206 Node* par = node->parent();
207
208 while ((par != nullptr) && (node->parentDir() == BinTreeDir::RIGHT_CHILD)) {
209 node = par;
210 par = par->parent();
211 }
212
213 return par;
214 }
215
216 template < typename Val, class Cmp, class Node >
217 INLINE Node* BinSearchTree< Val, Cmp, Node >::prevNode_(Node* node) const {
218 if (node == nullptr) return nullptr;
219
220 if (node->leftChild()) return maxNode_(node->leftChild());
221
222 Node* par = node->parent();
223
224 while ((par != nullptr) && (node->parentDir() == BinTreeDir::LEFT_CHILD)) {
225 node = par;
226 par = par->parent();
227 }
228
229 return par;
230 }
231
232 template < typename Val, class Cmp, class Node >
234 BinSearchTreeIterator< Val, Cmp, Node >::operator++() {
235 // if there is a current node, use it to compute the next node, else use
236 // directly next_node_ (this case obtains when the iterator was pointing
237 // toward a node that has been deleted before we use operator++)
238 node_ = node_ != nullptr ? tree_->succNode_(node_) : next_node_;
239
240 if (node_ == nullptr) {
241 next_node_ = nullptr;
242 prev_node_ = nullptr;
243 parent_ = nullptr;
244 left_child_ = nullptr;
245 right_child_ = nullptr;
246 }
247
248 return *this;
249 }
250
251 template < typename Val, class Cmp, class Node >
253 BinSearchTreeIterator< Val, Cmp, Node >::operator--() {
254 // if there is a current node, use it to compute the preceding node, else
255 // use
256 // directly prev_node_ (this case obtains when the iterator was pointing
257 // toward a node that has been deleted before we use operator--)
258 node_ = node_ != nullptr ? tree_->prevNode_(node_) : prev_node_;
259
260 if (node_ == nullptr) {
261 next_node_ = nullptr;
262 prev_node_ = nullptr;
263 parent_ = nullptr;
264 left_child_ = nullptr;
265 right_child_ = nullptr;
266 }
267
268 return *this;
269 }
270
271 template < typename Val, class Cmp, class Node >
272 INLINE bool BinSearchTreeIterator< Val, Cmp, Node >::operator==(
273 const BinSearchTreeIterator< Val, Cmp, Node >& from) const {
274 if (node_ != nullptr) return (node_ == from.node_);
275 else
276 return ((node_ == from.node_) && (tree_ == from.tree_) && (next_node_ == from.next_node_)
277 && (prev_node_ == from.prev_node_) && (parent_ == from.parent_)
278 && (left_child_ == from.left_child_) && (right_child_ == from.right_child_));
279 }
280
281 template < typename Val, class Cmp, class Node >
282 INLINE bool BinSearchTreeIterator< Val, Cmp, Node >::operator!=(
283 const BinSearchTreeIterator< Val, Cmp, Node >& from) const {
284 if (node_ != nullptr) return (node_ != from.node_);
285 else
286 return ((node_ != from.node_) || (tree_ != from.tree_) || (next_node_ != from.next_node_)
287 || (prev_node_ != from.prev_node_) || (parent_ != from.parent_)
288 || (left_child_ != from.left_child_) || (right_child_ != from.right_child_));
289 }
290
291 template < typename Val, class Cmp, class Node >
292 INLINE BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTreeIterator< Val, Cmp, Node >::up() {
293 // if there is a current node, use it to compute its parent node, else use
294 // directly parent_ (this case obtains when the iterator was pointing
295 // toward a node that has been deleted before we use operation up)
296 node_ = node_ != nullptr ? node_->parent() : parent_;
297
298 if (node_ == nullptr) {
299 next_node_ = nullptr;
300 prev_node_ = nullptr;
301 parent_ = nullptr;
302 left_child_ = nullptr;
303 right_child_ = nullptr;
304 }
305
306 return *this;
307 }
308
309 template < typename Val, class Cmp, class Node >
311 BinSearchTreeIterator< Val, Cmp, Node >::downLeft() {
312 // if there is a current node, use it to compute its left child, else use
313 // directly left_child_ (this case obtains when the iterator was pointing
314 // toward a node that has been deleted before we use operation downLeft)
315 node_ = node_ != nullptr ? node_->leftChild() : left_child_;
316
317 if (node_ == nullptr) {
318 next_node_ = nullptr;
319 prev_node_ = nullptr;
320 parent_ = nullptr;
321 left_child_ = nullptr;
322 right_child_ = nullptr;
323 }
324
325 return *this;
326 }
327
328 template < typename Val, class Cmp, class Node >
330 BinSearchTreeIterator< Val, Cmp, Node >::downRight() {
331 // if there is a current node, use it to compute its right child, else use
332 // directly right_child_ (this case obtains when the iterator was pointing
333 // toward a node that has been deleted before we use operation downRight)
334 node_ = node_ != nullptr ? node_->rightChild() : right_child_;
335
336 if (node_ == nullptr) {
337 next_node_ = nullptr;
338 prev_node_ = nullptr;
339 parent_ = nullptr;
340 left_child_ = nullptr;
341 right_child_ = nullptr;
342 }
343
344 return *this;
345 }
346
347 // ===========================================================================
348 // ===========================================================================
349 // === GENERIC BINARY SEARCH TREE ===
350 // ===========================================================================
351 // ===========================================================================
352
353 template < typename Val, class Cmp, class Node >
354 BinSearchTree< Val, Cmp, Node >::BinSearchTree(bool uniqueness_policy) :
355 root_(nullptr), iterator_list_(nullptr), uniqueness_policy_(uniqueness_policy),
356 nb_elements_(0) {
357 GUM_CONSTRUCTOR(BinSearchTree);
358 iter_end_.initialize_(this, nullptr, false);
359 }
360
361 template < typename Val, class Cmp, class Node >
362 BinSearchTree< Val, Cmp, Node >::BinSearchTree(const BinSearchTree< Val, Cmp, Node >& from) :
363 root_(nullptr), iterator_list_(nullptr), uniqueness_policy_(from.uniqueness_policy_) {
364 // for debugging purposes
365 GUM_CONS_CPY(BinSearchTree);
366
367 // copy the content of BinSearchTree "from"
368 root_ = copy_(from.root_);
369 nb_elements_ = from.nb_elements_;
370
371 // initialize the end/rend iterator
372 iter_end_.initialize_(this, nullptr, false);
373 }
374
375 template < typename Val, class Cmp, class Node >
376 INLINE void BinSearchTree< Val, Cmp, Node >::clear() {
377 // first we clear all the iterators, i.e., we detach them from the tree
378 for (iterator *iter = iterator_list_, *next_iter = nullptr; iter; iter = next_iter) {
379 next_iter = iter->next_iter_;
380 iter->clear();
381 }
382
383 // now, delete the whole tree
384 deleteSubTree_(root_);
385 root_ = nullptr;
386 nb_elements_ = 0;
387
388 // note that there is no need to redefined end/rend as they do not rely
389 // on the content of the tree
390 }
391
392 template < typename Val, class Cmp, class Node >
393 BinSearchTree< Val, Cmp, Node >&
394 BinSearchTree< Val, Cmp, Node >::operator=(const BinSearchTree< Val, Cmp, Node >& from) {
395 // avoid self assignment
396 if (this != &from) {
397 // for debugging purposes
398 GUM_OP_CPY(BinSearchTree);
399
400 // if the tree is not currently empty, remove it
401 clear();
402
403 // copy binary tree "from"
404 uniqueness_policy_ = from.uniqueness_policy_;
405 root_ = copy_(from.root_); // note that we can copy from's tree structure
406 // as from and this have the same ordering cmp_
407 nb_elements_ = from.nb_elements_;
408
409 // note that we do not need to update the end/rend iterator as, besides
410 // field tree_, no other field is related to the current tree (i.e., all
411 // _*node_ are set to nullptr
412 }
413
414 return *this;
415 }
416
417 template < typename Val, class Cmp, class Node >
418 BinSearchTree< Val, Cmp, Node >::~BinSearchTree() {
419 // for debugging purposes
420 GUM_DESTRUCTOR(BinSearchTree);
421
422 // clear all the iterators and remove all nodes
423 clear();
424 }
425
426 template < typename Val, class Cmp, class Node >
427 Node* BinSearchTree< Val, Cmp, Node >::copy_(Node* node, Node* parent, BinTreeDir dir) {
428 // if there is no node to copy, abort
429 if (!node) return nullptr;
430
431 // create the copy of node
432 Node* new_node = new Node(*node);
433
434 if (parent) parent->insertChild(*new_node, dir);
435
436 // if necessary, create the left and right subgraphs
437 copy_(node->leftChild(), new_node, BinTreeDir::LEFT_CHILD);
438 copy_(node->rightChild(), new_node, BinTreeDir::RIGHT_CHILD);
439
440 return new_node;
441 }
442
443 template < typename Val, class Cmp, class Node >
444 void BinSearchTree< Val, Cmp, Node >::deleteSubTree_(Node* node) {
445 // if there is no node to remove, return
446 if (!node) return;
447
448 // delete the left and right subgraphs
449 deleteSubTree_(node->leftChild());
450 deleteSubTree_(node->rightChild());
451
452 // delete the node itself
453 delete node;
454 }
455
456 template < typename Val, class Cmp, class Node >
457 INLINE Node* BinSearchTree< Val, Cmp, Node >::insert_(const Val& val) {
458 // if the tree is not empty, search the binary search tree to know
459 // where the node should be inserted
460 if (root_) {
461 Node* node = root_;
462
463 while (true) {
464 if (cmp_(val, node->value()))
465 if (!node->leftChild()) {
466 // here we are on a leaf => insert the new node
467 ++nb_elements_;
468 return node->insertLeftChild(val);
469 } else {
470 node = node->leftChild();
471 }
472 else if (cmp_(node->value(), val) || !uniqueness_policy_)
473 if (!node->rightChild()) {
474 // here we are on a leaf => insert the new node
475 ++nb_elements_;
476 return node->insertRightChild(val);
477 } else {
478 node = node->rightChild();
479 }
480 else {
481 // here we found a node with the same key and the uniqueness policy
482 // is set. So we should raise an exception
483 GUM_ERROR(DuplicateElement, "Val " << val << " already in the binary search tree")
484 }
485 }
486 }
487
488 // here the tree is empty, just create a new node
489 root_ = new Node(val);
490 ++nb_elements_;
491 return root_;
492 }
493
494 template < typename Val, class Cmp, class Node >
495 INLINE const Val& BinSearchTree< Val, Cmp, Node >::insert(const Val& val) {
496 return insert_(val)->value();
497 }
498
499 template < typename Val, class Cmp, class Node >
500 INLINE const Val& BinSearchTree< Val, Cmp, Node >::rootValue() const {
501 if (root_ == nullptr) { GUM_ERROR(NotFound, "no value in an empty Binary Search tree") }
502
503 return root_->value();
504 }
505
506 template < typename Val, class Cmp, class Node >
507 INLINE const Val& BinSearchTree< Val, Cmp, Node >::minValue() const {
508 if (root_ == nullptr) { GUM_ERROR(NotFound, "no minimal value in an empty Binary Search tree") }
509
510 return minNode_(root_)->value();
511 }
512
513 template < typename Val, class Cmp, class Node >
514 INLINE const Val& BinSearchTree< Val, Cmp, Node >::maxValue() const {
515 if (root_ == nullptr) { GUM_ERROR(NotFound, "no maximal value in an empty Binary Search tree") }
516
517 return maxNode_(root_)->value();
518 }
519
520 template < typename Val, class Cmp, class Node >
521 INLINE Node* BinSearchTree< Val, Cmp, Node >::getNode_(const Val& val) const {
522 // if the tree is not empty, search the binary search tree to know
523 // where the node could be
524 if (root_) {
525 Node* node = root_;
526
527 while (true) {
528 if (cmp_(val, node->value())) {
529 if (!node->leftChild()) return nullptr;
530 else node = node->leftChild();
531 } else if (cmp_(node->value(), val)) {
532 if (!node->rightChild()) return nullptr;
533 else node = node->rightChild();
534 } else return node;
535 }
536 } else {
537 return nullptr;
538 }
539 }
540
541 template < typename Val, class Cmp, class Node >
542 INLINE bool BinSearchTree< Val, Cmp, Node >::contains(const Val& val) const {
543 return (getNode_(val) != nullptr);
544 }
545
546 template < typename Val, class Cmp, class Node >
547 INLINE Size BinSearchTree< Val, Cmp, Node >::size() const {
548 return nb_elements_;
549 }
550
551 template < typename Val, class Cmp, class Node >
552 INLINE bool BinSearchTree< Val, Cmp, Node >::empty() const {
553 return (nb_elements_ == 0);
554 }
555
556 template < typename Val, class Cmp, class Node >
557 std::string BinSearchTree< Val, Cmp, Node >::toString() const {
558 bool deja = false;
559 std::stringstream stream;
560 stream << "[";
561
562 for (const_iterator iter = begin(); iter != end(); ++iter, deja = true) {
563 if (deja) stream << " , ";
564
565 stream << *iter;
566 }
567
568 stream << "]";
569
570 return stream.str();
571 }
572
573 template < typename Val, class Cmp, class Node >
574 INLINE bool BinSearchTree< Val, Cmp, Node >::uniquenessPolicy() const {
575 return uniqueness_policy_;
576 }
577
578 template < typename Val, class Cmp, class Node >
579 INLINE void BinSearchTree< Val, Cmp, Node >::setUniquenessPolicy(const bool new_policy) {
580 uniqueness_policy_ = new_policy;
581 }
582
583 template < typename Val, class Cmp, class Node >
584 INLINE BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::begin() {
586 iter.initialize_(this, minNode_(root_), true);
587 return iter;
588 }
589
590 template < typename Val, class Cmp, class Node >
591 INLINE BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::begin() const {
593 iter.initialize_(this, minNode_(root_), true);
594 return iter;
595 }
596
597 template < typename Val, class Cmp, class Node >
598 INLINE BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::rbegin() {
600 iter.initialize_(this, maxNode_(root_), true);
601 return iter;
602 }
603
604 template < typename Val, class Cmp, class Node >
605 INLINE BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::rbegin() const {
607 iter.initialize_(this, maxNode_(root_), true);
608 return iter;
609 }
610
611 template < typename Val, class Cmp, class Node >
612 INLINE const BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTree< Val, Cmp, Node >::end() {
613 return iter_end_;
614 }
615
616 template < typename Val, class Cmp, class Node >
618 BinSearchTree< Val, Cmp, Node >::end() const {
619 return iter_end_;
620 }
621
622 template < typename Val, class Cmp, class Node >
623 INLINE const BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTree< Val, Cmp, Node >::rend() {
624 return iter_end_;
625 }
626
627 template < typename Val, class Cmp, class Node >
629 BinSearchTree< Val, Cmp, Node >::rend() const {
630 return iter_end_;
631 }
632
633 template < typename Val, class Cmp, class Node >
634 INLINE BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::root() {
636 iter.initialize_(this, root_, true);
637 return iter;
638 }
639
640 template < typename Val, class Cmp, class Node >
641 INLINE BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::root() const {
643 iter.initialize_(this, root_, true);
644 return iter;
645 }
646
647 template < typename Val, class Cmp, class Node >
648 void BinSearchTree< Val, Cmp, Node >::erase_(Node* node) {
649 if (!node) return;
650
651 // update all the iterators pointing to node that they should point
652 // elsewhere
653 _updateEraseIterators_(node);
654
655 // update the number of elements contained in the tree
656 --nb_elements_;
657
658 // now remove the node from the tree:
659
660 // if the node has no children, then just remove it
661 if (!node->leftChild() && !node->rightChild()) {
662 // if the node was the only one in the tree, then the tree becomes empty
663 if (!node->parent()) root_ = nullptr;
664
665 // note that, when node has a parent, there is no need to remove the
666 // link between node and this parent: this will be taken care of by
667 // node's destructor.
668 }
669 // if there is just a right child
670 else if (!node->leftChild()) {
671 // just relink the right child with the parent (if any)
672 if (!node->parent()) {
673 // in this case, no need to remove the link between "node" and its
674 // child:
675 // this will be taken care of by the destructor of "node"
676 root_ = node->rightChild();
677 } else {
678 Node * parent = node->parent(), *child = node->rightChild();
679 BinTreeDir dir = node->parentDir();
680 parent->eraseLink(dir);
681 node->eraseRightLink();
682 parent->insertChild(*child, dir);
683 }
684 }
685 // if there is just a left child
686 else if (!node->rightChild()) {
687 // just relink the left child with the parent (if any)
688 if (!node->parent()) {
689 // in this case, no need to remove the link between "node" and its
690 // child:
691 // this will be taken care of by the destructor of "node"
692 root_ = node->leftChild();
693 } else {
694 Node * parent = node->parent(), *child = node->leftChild();
695 BinTreeDir dir = node->parentDir();
696 parent->eraseLink(dir);
697 node->eraseLeftLink();
698 parent->insertChild(*child, dir);
699 }
700 }
701 // ok, here there are two children
702 else {
703 _eraseWithTwoChildren_(node);
704 }
705
706 // now we shall physically remove node from memory
707 delete node;
708 }
709
710 template < typename Val, class Cmp, class Node >
711 INLINE void BinSearchTree< Val, Cmp, Node >::_eraseWithTwoChildren_(Node* node) {
712 // the idea is to get the successor of "node" and substitute "node" by
713 // it. As "node" has two children, we are sure that the successor is one
714 // of node's descendants. Moreover, by its very definition, this
715 // successor has no left child. Hence, two cases can obtain:
716 // 1/ the successor is precisely node's right child. In this case, we just
717 // have to make node's left child be the left child of the successor,
718 // and node's parent be the successor's parent, and the tree is again
719 // a binary search tree.
720 // 2/ the successor is not node's right child. In this case, we know that
721 // the successor has a parent different from node and that the
722 // successor
723 // is a left child of this parent. We just need to put the right child
724 // of the successor (if any) as the left child of its parent, and to
725 // replace "node" by the successor.
726 Node* successor = succNode_(node);
727
728 if (successor == node->rightChild()) { // proceed to case 1:
729 Node* left_child = node->leftChild();
730 node->eraseLeftLink();
731 node->eraseRightLink();
732 successor->insertLeftChild(*left_child);
733
734 if (!node->parent()) {
735 // in this case, no need to remove the link between "node" and the
736 // successor: this will be taken care of by the destructor of "node"
737 root_ = successor;
738 } else {
739 // rechain node's parent with its successor
740 BinTreeDir par_dir = node->parentDir();
741 Node* parent = node->parent();
742 parent->eraseLink(par_dir);
743 parent->insertChild(*successor, par_dir);
744 }
745 } else { // proceed to case 2:
746 Node* parent = successor->parent();
747 parent->eraseLeftLink();
748
749 if (successor->rightChild()) {
750 Node* succ_child = successor->rightChild();
751 successor->eraseRightLink();
752 parent->insertLeftChild(*succ_child);
753 }
754
755 Node *left = node->leftChild(), *right = node->rightChild();
756 node->eraseLeftLink();
757 node->eraseRightLink();
758 successor->insertLeftChild(*left);
759 successor->insertRightChild(*right);
760
761 if (!node->parent()) {
762 root_ = successor;
763 } else {
764 // rechain node's parent with its successor
765 BinTreeDir par_dir = node->parentDir();
766 Node* parent = node->parent();
767 parent->eraseLink(par_dir);
768 parent->insertChild(*successor, par_dir);
769 }
770 }
771 }
772
773 template < typename Val, class Cmp, class Node >
774 INLINE void BinSearchTree< Val, Cmp, Node >::erase(const Val& val) {
775 Node* n = getNode_(val);
776
777 if (n == nullptr) GUM_ERROR(gum::NotFound, "Value \"" << val << "\" not found")
778
779 erase_(n);
780 }
781
782 template < typename Val, class Cmp, class Node >
783 INLINE void BinSearchTree< Val, Cmp, Node >::erase(const iterator& iter) {
784 erase_(iter.node_);
785 }
786
787 template < typename Val, class Cmp, class Node >
788 void BinSearchTree< Val, Cmp, Node >::_updateEraseIterators_(Node* node) {
789 for (iterator* iter = iterator_list_; iter; iter = iter->next_iter_) {
790 // if the iterator points toward the node to be deleted, make its node_
791 // field point to nullptr and update accordingly its other fields
792 if (iter->node_ == node) {
793 iter->node_ = nullptr;
794 iter->next_node_ = succNode_(node);
795 iter->prev_node_ = prevNode_(node);
796 iter->parent_ = node->parent();
797 iter->left_child_ = node->leftChild();
798 iter->right_child_ = node->rightChild();
799 } else if (!iter->node_) {
800 if (iter->next_node_ == node) iter->next_node_ = succNode_(node);
801
802 if (iter->prev_node_ == node) iter->prev_node_ = prevNode_(node);
803
804 if (iter->parent_ == node) iter->parent_ = node->parent();
805
806 if (iter->left_child_ == node) iter->left_child_ = node->leftChild();
807
808 if (iter->right_child_ == node) iter->right_child_ = node->rightChild();
809 }
810 }
811 }
812
813} // namespace gum
814
815#endif // DOXYGEN_SHOULD_SKIP_THIS
Basic binary search trees.
BinSearchTreeIterator()
Class Constructors and Destructors.
Exception : a similar element already exists.
Exception : the element we looked for cannot be found.
aGrUM's exceptions
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
gum is the global namespace for all aGrUM entities
Definition agrum.h:46