aGrUM 3.1.1
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-2026 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-2026 *
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
41#pragma once
42
43
50
51#include <sstream>
52#include <string>
53
56
57#ifndef DOXYGEN_SHOULD_SKIP_THIS
58
59namespace gum {
60
61 // ===========================================================================
62 // ===========================================================================
63 // === GENERIC BINARY SEARCH TREE ITERATORS ===
64 // ===========================================================================
65 // ===========================================================================
66
67 template < typename Val, class Cmp, class Node >
69 node_(nullptr), next_node_(nullptr), prev_node_(nullptr), parent_(nullptr),
70 left_child_(nullptr), right_child_(nullptr), tree_(nullptr), next_iter_(nullptr) {
71 GUM_CONSTRUCTOR(BinSearchTreeIterator);
72 }
73
74 template < typename Val, class Cmp, class Node >
75 BinSearchTreeIterator< Val, Cmp, Node >::BinSearchTreeIterator(
77 node_(from.node_), next_node_(from.next_node_), prev_node_(from.prev_node_),
78 parent_(from.parent_), left_child_(from.left_child_), right_child_(from.right_child_),
79 tree_(from.tree_) {
80 GUM_CONS_CPY(BinSearchTreeIterator);
81
82 if (tree_ != nullptr) {
83 next_iter_ = tree_->iterator_list_;
84 tree_->iterator_list_ = this;
85 } else next_iter_ = nullptr;
86 }
87
88 template < typename Val, class Cmp, class Node >
89 void BinSearchTreeIterator< Val, Cmp, Node >::initialize_(
90 const BinSearchTree< Val, Cmp, Node >* tree,
91 const Node* current_node,
92 bool add_to_iterator_list) {
93 // remember: we do not check here whether the iterator already belongs to
94 // a tree. We assume that it is not so.
95
96 tree_ = const_cast< BinSearchTree< Val, Cmp, Node >* >(tree);
97 node_ = const_cast< Node* >(current_node);
98
99 if (add_to_iterator_list && (tree_ != nullptr)) {
100 next_iter_ = tree_->iterator_list_;
101 tree_->iterator_list_ = this;
102 }
103 }
104
105 template < typename Val, class Cmp, class Node >
106 void BinSearchTreeIterator< Val, Cmp, Node >::detachFromTree_() {
107 if (tree_ != nullptr) {
108 BinSearchTreeIterator< Val, Cmp, Node >*iter, *prev_iter = nullptr;
109
110 for (iter = tree_->iterator_list_; iter != this && iter != nullptr;
111 prev_iter = iter, iter = iter->next_iter_) {}
112
113 if (iter != nullptr) {
114 if (prev_iter != nullptr) prev_iter->next_iter_ = next_iter_;
115 else tree_->iterator_list_ = next_iter_;
116 }
117 }
118 }
119
120 template < typename Val, class Cmp, class Node >
121 BinSearchTreeIterator< Val, Cmp, Node >::~BinSearchTreeIterator() {
122 GUM_DESTRUCTOR(BinSearchTreeIterator);
123
124 // remove the iterator from its tree iterator's list
125 detachFromTree_();
126 }
127
128 template < typename Val, class Cmp, class Node >
129 void BinSearchTreeIterator< Val, Cmp, Node >::clear() {
130 // remove the iterator from its tree iterator's list
131 detachFromTree_();
132
133 // reset the iterator
134 node_ = nullptr;
135 next_node_ = nullptr;
136 prev_node_ = nullptr;
137 parent_ = nullptr;
138 left_child_ = nullptr;
139 right_child_ = nullptr;
140 tree_ = nullptr;
141 next_iter_ = nullptr;
142 }
143
144 template < typename Val, class Cmp, class Node >
145 BinSearchTreeIterator< Val, Cmp, Node >& 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 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 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 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 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 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 >
233 BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTreeIterator< Val, Cmp, Node >::operator++() {
234 // if there is a current node, use it to compute the next node, else use
235 // directly next_node_ (this case obtains when the iterator was pointing
236 // toward a node that has been deleted before we use operator++)
237 node_ = node_ != nullptr ? tree_->succNode_(node_) : next_node_;
238
239 if (node_ == nullptr) {
240 next_node_ = nullptr;
241 prev_node_ = nullptr;
242 parent_ = nullptr;
243 left_child_ = nullptr;
244 right_child_ = nullptr;
245 }
246
247 return *this;
248 }
249
250 template < typename Val, class Cmp, class Node >
251 BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTreeIterator< Val, Cmp, Node >::operator--() {
252 // if there is a current node, use it to compute the preceding node, else
253 // use
254 // directly prev_node_ (this case obtains when the iterator was pointing
255 // toward a node that has been deleted before we use operator--)
256 node_ = node_ != nullptr ? tree_->prevNode_(node_) : prev_node_;
257
258 if (node_ == nullptr) {
259 next_node_ = nullptr;
260 prev_node_ = nullptr;
261 parent_ = nullptr;
262 left_child_ = nullptr;
263 right_child_ = nullptr;
264 }
265
266 return *this;
267 }
268
269 template < typename Val, class Cmp, class Node >
270 bool BinSearchTreeIterator< Val, Cmp, Node >::operator==(
271 const BinSearchTreeIterator< Val, Cmp, Node >& from) const {
272 if (node_ != nullptr) return (node_ == from.node_);
273 else
274 return ((node_ == from.node_) && (tree_ == from.tree_) && (next_node_ == from.next_node_)
275 && (prev_node_ == from.prev_node_) && (parent_ == from.parent_)
276 && (left_child_ == from.left_child_) && (right_child_ == from.right_child_));
277 }
278
279 template < typename Val, class Cmp, class Node >
280 bool BinSearchTreeIterator< Val, Cmp, Node >::operator!=(
281 const BinSearchTreeIterator< Val, Cmp, Node >& from) const {
282 if (node_ != nullptr) return (node_ != from.node_);
283 else
284 return ((node_ != from.node_) || (tree_ != from.tree_) || (next_node_ != from.next_node_)
285 || (prev_node_ != from.prev_node_) || (parent_ != from.parent_)
286 || (left_child_ != from.left_child_) || (right_child_ != from.right_child_));
287 }
288
289 template < typename Val, class Cmp, class Node >
290 BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTreeIterator< Val, Cmp, Node >::up() {
291 // if there is a current node, use it to compute its parent node, else use
292 // directly parent_ (this case obtains when the iterator was pointing
293 // toward a node that has been deleted before we use operation up)
294 node_ = node_ != nullptr ? node_->parent() : parent_;
295
296 if (node_ == nullptr) {
297 next_node_ = nullptr;
298 prev_node_ = nullptr;
299 parent_ = nullptr;
300 left_child_ = nullptr;
301 right_child_ = nullptr;
302 }
303
304 return *this;
305 }
306
307 template < typename Val, class Cmp, class Node >
308 BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTreeIterator< Val, Cmp, Node >::downLeft() {
309 // if there is a current node, use it to compute its left child, else use
310 // directly left_child_ (this case obtains when the iterator was pointing
311 // toward a node that has been deleted before we use operation downLeft)
312 node_ = node_ != nullptr ? node_->leftChild() : left_child_;
313
314 if (node_ == nullptr) {
315 next_node_ = nullptr;
316 prev_node_ = nullptr;
317 parent_ = nullptr;
318 left_child_ = nullptr;
319 right_child_ = nullptr;
320 }
321
322 return *this;
323 }
324
325 template < typename Val, class Cmp, class Node >
326 BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTreeIterator< Val, Cmp, Node >::downRight() {
327 // if there is a current node, use it to compute its right child, else use
328 // directly right_child_ (this case obtains when the iterator was pointing
329 // toward a node that has been deleted before we use operation downRight)
330 node_ = node_ != nullptr ? node_->rightChild() : right_child_;
331
332 if (node_ == nullptr) {
333 next_node_ = nullptr;
334 prev_node_ = nullptr;
335 parent_ = nullptr;
336 left_child_ = nullptr;
337 right_child_ = nullptr;
338 }
339
340 return *this;
341 }
342
343 // ===========================================================================
344 // ===========================================================================
345 // === GENERIC BINARY SEARCH TREE ===
346 // ===========================================================================
347 // ===========================================================================
348
349 template < typename Val, class Cmp, class Node >
350 BinSearchTree< Val, Cmp, Node >::BinSearchTree(bool uniqueness_policy) :
351 root_(nullptr), iterator_list_(nullptr), uniqueness_policy_(uniqueness_policy),
352 nb_elements_(0) {
353 GUM_CONSTRUCTOR(BinSearchTree);
354 iter_end_.initialize_(this, nullptr, false);
355 }
356
357 template < typename Val, class Cmp, class Node >
358 BinSearchTree< Val, Cmp, Node >::BinSearchTree(const BinSearchTree< Val, Cmp, Node >& from) :
359 root_(nullptr), iterator_list_(nullptr), uniqueness_policy_(from.uniqueness_policy_) {
360 // for debugging purposes
361 GUM_CONS_CPY(BinSearchTree);
362
363 // copy the content of BinSearchTree "from"
364 root_ = copy_(from.root_);
365 nb_elements_ = from.nb_elements_;
366
367 // initialize the end/rend iterator
368 iter_end_.initialize_(this, nullptr, false);
369 }
370
371 template < typename Val, class Cmp, class Node >
372 void BinSearchTree< Val, Cmp, Node >::clear() {
373 // first we clear all the iterators, i.e., we detach them from the tree
374 for (iterator *iter = iterator_list_, *next_iter = nullptr; iter; iter = next_iter) {
375 next_iter = iter->next_iter_;
376 iter->clear();
377 }
378
379 // now, delete the whole tree
380 deleteSubTree_(root_);
381 root_ = nullptr;
382 nb_elements_ = 0;
383
384 // note that there is no need to redefined end/rend as they do not rely
385 // on the content of the tree
386 }
387
388 template < typename Val, class Cmp, class Node >
389 BinSearchTree< Val, Cmp, Node >&
390 BinSearchTree< Val, Cmp, Node >::operator=(const BinSearchTree< Val, Cmp, Node >& from) {
391 // avoid self assignment
392 if (this != &from) {
393 // for debugging purposes
394 GUM_OP_CPY(BinSearchTree);
395
396 // if the tree is not currently empty, remove it
397 clear();
398
399 // copy binary tree "from"
400 uniqueness_policy_ = from.uniqueness_policy_;
401 root_ = copy_(from.root_); // note that we can copy from's tree structure
402 // as from and this have the same ordering cmp_
403 nb_elements_ = from.nb_elements_;
404
405 // note that we do not need to update the end/rend iterator as, besides
406 // field tree_, no other field is related to the current tree (i.e., all
407 // _*node_ are set to nullptr
408 }
409
410 return *this;
411 }
412
413 template < typename Val, class Cmp, class Node >
414 BinSearchTree< Val, Cmp, Node >::~BinSearchTree() {
415 // for debugging purposes
416 GUM_DESTRUCTOR(BinSearchTree);
417
418 // clear all the iterators and remove all nodes
419 clear();
420 }
421
422 template < typename Val, class Cmp, class Node >
423 Node* BinSearchTree< Val, Cmp, Node >::copy_(Node* node, Node* parent, BinTreeDir dir) {
424 // if there is no node to copy, abort
425 if (!node) return nullptr;
426
427 // create the copy of node
428 Node* new_node = new Node(*node);
429
430 if (parent) parent->insertChild(*new_node, dir);
431
432 // if necessary, create the left and right subgraphs
433 copy_(node->leftChild(), new_node, BinTreeDir::LEFT_CHILD);
434 copy_(node->rightChild(), new_node, BinTreeDir::RIGHT_CHILD);
435
436 return new_node;
437 }
438
439 template < typename Val, class Cmp, class Node >
440 void BinSearchTree< Val, Cmp, Node >::deleteSubTree_(Node* node) {
441 // if there is no node to remove, return
442 if (!node) return;
443
444 // delete the left and right subgraphs
445 deleteSubTree_(node->leftChild());
446 deleteSubTree_(node->rightChild());
447
448 // delete the node itself
449 delete node;
450 }
451
452 template < typename Val, class Cmp, class Node >
453 Node* BinSearchTree< Val, Cmp, Node >::insert_(const Val& val) {
454 // if the tree is not empty, search the binary search tree to know
455 // where the node should be inserted
456 if (root_) {
457 Node* node = root_;
458
459 while (true) {
460 if (cmp_(val, node->value()))
461 if (!node->leftChild()) {
462 // here we are on a leaf => insert the new node
463 ++nb_elements_;
464 return node->insertLeftChild(val);
465 } else {
466 node = node->leftChild();
467 }
468 else if (cmp_(node->value(), val) || !uniqueness_policy_)
469 if (!node->rightChild()) {
470 // here we are on a leaf => insert the new node
471 ++nb_elements_;
472 return node->insertRightChild(val);
473 } else {
474 node = node->rightChild();
475 }
476 else {
477 // here we found a node with the same key and the uniqueness policy
478 // is set. So we should raise an exception
479 GUM_ERROR(DuplicateElement, "Val " << val << " already in the binary search tree")
480 }
481 }
482 }
483
484 // here the tree is empty, just create a new node
485 root_ = new Node(val);
486 ++nb_elements_;
487 return root_;
488 }
489
490 template < typename Val, class Cmp, class Node >
491 const Val& BinSearchTree< Val, Cmp, Node >::insert(const Val& val) {
492 return insert_(val)->value();
493 }
494
495 template < typename Val, class Cmp, class Node >
496 const Val& BinSearchTree< Val, Cmp, Node >::rootValue() const {
497 if (root_ == nullptr) { GUM_ERROR(NotFound, "no value in an empty Binary Search tree") }
498
499 return root_->value();
500 }
501
502 template < typename Val, class Cmp, class Node >
503 const Val& BinSearchTree< Val, Cmp, Node >::minValue() const {
504 if (root_ == nullptr) { GUM_ERROR(NotFound, "no minimal value in an empty Binary Search tree") }
505
506 return minNode_(root_)->value();
507 }
508
509 template < typename Val, class Cmp, class Node >
510 const Val& BinSearchTree< Val, Cmp, Node >::maxValue() const {
511 if (root_ == nullptr) { GUM_ERROR(NotFound, "no maximal value in an empty Binary Search tree") }
512
513 return maxNode_(root_)->value();
514 }
515
516 template < typename Val, class Cmp, class Node >
517 Node* BinSearchTree< Val, Cmp, Node >::getNode_(const Val& val) const {
518 // if the tree is not empty, search the binary search tree to know
519 // where the node could be
520 if (root_) {
521 Node* node = root_;
522
523 while (true) {
524 if (cmp_(val, node->value())) {
525 if (!node->leftChild()) return nullptr;
526 else node = node->leftChild();
527 } else if (cmp_(node->value(), val)) {
528 if (!node->rightChild()) return nullptr;
529 else node = node->rightChild();
530 } else return node;
531 }
532 } else {
533 return nullptr;
534 }
535 }
536
537 template < typename Val, class Cmp, class Node >
538 bool BinSearchTree< Val, Cmp, Node >::contains(const Val& val) const {
539 return (getNode_(val) != nullptr);
540 }
541
542 template < typename Val, class Cmp, class Node >
543 Size BinSearchTree< Val, Cmp, Node >::size() const {
544 return nb_elements_;
545 }
546
547 template < typename Val, class Cmp, class Node >
548 bool BinSearchTree< Val, Cmp, Node >::empty() const {
549 return (nb_elements_ == 0);
550 }
551
552 template < typename Val, class Cmp, class Node >
553 std::string BinSearchTree< Val, Cmp, Node >::toString() const {
554 bool deja = false;
555 std::stringstream stream;
556 stream << "[";
557
558 for (const_iterator iter = begin(); iter != end(); ++iter, deja = true) {
559 if (deja) stream << " , ";
560
561 stream << *iter;
562 }
563
564 stream << "]";
565
566 return stream.str();
567 }
568
569 template < typename Val, class Cmp, class Node >
570 bool BinSearchTree< Val, Cmp, Node >::uniquenessPolicy() const {
571 return uniqueness_policy_;
572 }
573
574 template < typename Val, class Cmp, class Node >
575 void BinSearchTree< Val, Cmp, Node >::setUniquenessPolicy(const bool new_policy) {
576 uniqueness_policy_ = new_policy;
577 }
578
579 template < typename Val, class Cmp, class Node >
580 BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::begin() {
582 iter.initialize_(this, minNode_(root_), true);
583 return iter;
584 }
585
586 template < typename Val, class Cmp, class Node >
587 BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::begin() const {
589 iter.initialize_(this, minNode_(root_), true);
590 return iter;
591 }
592
593 template < typename Val, class Cmp, class Node >
594 BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::rbegin() {
596 iter.initialize_(this, maxNode_(root_), true);
597 return iter;
598 }
599
600 template < typename Val, class Cmp, class Node >
601 BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::rbegin() const {
603 iter.initialize_(this, maxNode_(root_), true);
604 return iter;
605 }
606
607 template < typename Val, class Cmp, class Node >
608 const BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTree< Val, Cmp, Node >::end() {
609 return iter_end_;
610 }
611
612 template < typename Val, class Cmp, class Node >
613 const BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTree< Val, Cmp, Node >::end() const {
614 return iter_end_;
615 }
616
617 template < typename Val, class Cmp, class Node >
618 const BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTree< Val, Cmp, Node >::rend() {
619 return iter_end_;
620 }
621
622 template < typename Val, class Cmp, class Node >
623 const BinSearchTreeIterator< Val, Cmp, Node >& BinSearchTree< Val, Cmp, Node >::rend() const {
624 return iter_end_;
625 }
626
627 template < typename Val, class Cmp, class Node >
628 BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::root() {
630 iter.initialize_(this, root_, true);
631 return iter;
632 }
633
634 template < typename Val, class Cmp, class Node >
635 BinSearchTreeIterator< Val, Cmp, Node > BinSearchTree< Val, Cmp, Node >::root() const {
637 iter.initialize_(this, root_, true);
638 return iter;
639 }
640
641 template < typename Val, class Cmp, class Node >
642 void BinSearchTree< Val, Cmp, Node >::erase_(Node* node) {
643 if (!node) return;
644
645 // update all the iterators pointing to node that they should point
646 // elsewhere
647 _updateEraseIterators_(node);
648
649 // update the number of elements contained in the tree
650 --nb_elements_;
651
652 // now remove the node from the tree:
653
654 // if the node has no children, then just remove it
655 if (!node->leftChild() && !node->rightChild()) {
656 // if the node was the only one in the tree, then the tree becomes empty
657 if (!node->parent()) root_ = nullptr;
658
659 // note that, when node has a parent, there is no need to remove the
660 // link between node and this parent: this will be taken care of by
661 // node's destructor.
662 }
663 // if there is just a right child
664 else if (!node->leftChild()) {
665 // just relink the right child with the parent (if any)
666 if (!node->parent()) {
667 // in this case, no need to remove the link between "node" and its
668 // child:
669 // this will be taken care of by the destructor of "node"
670 root_ = node->rightChild();
671 } else {
672 Node * parent = node->parent(), *child = node->rightChild();
673 BinTreeDir dir = node->parentDir();
674 parent->eraseLink(dir);
675 node->eraseRightLink();
676 parent->insertChild(*child, dir);
677 }
678 }
679 // if there is just a left child
680 else if (!node->rightChild()) {
681 // just relink the left child with the parent (if any)
682 if (!node->parent()) {
683 // in this case, no need to remove the link between "node" and its
684 // child:
685 // this will be taken care of by the destructor of "node"
686 root_ = node->leftChild();
687 } else {
688 Node * parent = node->parent(), *child = node->leftChild();
689 BinTreeDir dir = node->parentDir();
690 parent->eraseLink(dir);
691 node->eraseLeftLink();
692 parent->insertChild(*child, dir);
693 }
694 }
695 // ok, here there are two children
696 else {
697 _eraseWithTwoChildren_(node);
698 }
699
700 // now we shall physically remove node from memory
701 delete node;
702 }
703
704 template < typename Val, class Cmp, class Node >
705 void BinSearchTree< Val, Cmp, Node >::_eraseWithTwoChildren_(Node* node) {
706 // the idea is to get the successor of "node" and substitute "node" by
707 // it. As "node" has two children, we are sure that the successor is one
708 // of node's descendants. Moreover, by its very definition, this
709 // successor has no left child. Hence, two cases can obtain:
710 // 1/ the successor is precisely node's right child. In this case, we just
711 // have to make node's left child be the left child of the successor,
712 // and node's parent be the successor's parent, and the tree is again
713 // a binary search tree.
714 // 2/ the successor is not node's right child. In this case, we know that
715 // the successor has a parent different from node and that the
716 // successor
717 // is a left child of this parent. We just need to put the right child
718 // of the successor (if any) as the left child of its parent, and to
719 // replace "node" by the successor.
720 Node* successor = succNode_(node);
721
722 if (successor == node->rightChild()) { // proceed to case 1:
723 Node* left_child = node->leftChild();
724 node->eraseLeftLink();
725 node->eraseRightLink();
726 successor->insertLeftChild(*left_child);
727
728 if (!node->parent()) {
729 // in this case, no need to remove the link between "node" and the
730 // successor: this will be taken care of by the destructor of "node"
731 root_ = successor;
732 } else {
733 // rechain node's parent with its successor
734 BinTreeDir par_dir = node->parentDir();
735 Node* parent = node->parent();
736 parent->eraseLink(par_dir);
737 parent->insertChild(*successor, par_dir);
738 }
739 } else { // proceed to case 2:
740 Node* parent = successor->parent();
741 parent->eraseLeftLink();
742
743 if (successor->rightChild()) {
744 Node* succ_child = successor->rightChild();
745 successor->eraseRightLink();
746 parent->insertLeftChild(*succ_child);
747 }
748
749 Node *left = node->leftChild(), *right = node->rightChild();
750 node->eraseLeftLink();
751 node->eraseRightLink();
752 successor->insertLeftChild(*left);
753 successor->insertRightChild(*right);
754
755 if (!node->parent()) {
756 root_ = successor;
757 } else {
758 // rechain node's parent with its successor
759 BinTreeDir par_dir = node->parentDir();
760 Node* parent = node->parent();
761 parent->eraseLink(par_dir);
762 parent->insertChild(*successor, par_dir);
763 }
764 }
765 }
766
767 template < typename Val, class Cmp, class Node >
768 void BinSearchTree< Val, Cmp, Node >::erase(const Val& val) {
769 Node* n = getNode_(val);
770
771 if (n == nullptr) GUM_ERROR(gum::NotFound, "Value \"" << val << "\" not found")
772
773 erase_(n);
774 }
775
776 template < typename Val, class Cmp, class Node >
777 void BinSearchTree< Val, Cmp, Node >::erase(const iterator& iter) {
778 erase_(iter.node_);
779 }
780
781 template < typename Val, class Cmp, class Node >
782 void BinSearchTree< Val, Cmp, Node >::_updateEraseIterators_(Node* node) {
783 for (iterator* iter = iterator_list_; iter; iter = iter->next_iter_) {
784 // if the iterator points toward the node to be deleted, make its node_
785 // field point to nullptr and update accordingly its other fields
786 if (iter->node_ == node) {
787 iter->node_ = nullptr;
788 iter->next_node_ = succNode_(node);
789 iter->prev_node_ = prevNode_(node);
790 iter->parent_ = node->parent();
791 iter->left_child_ = node->leftChild();
792 iter->right_child_ = node->rightChild();
793 } else if (!iter->node_) {
794 if (iter->next_node_ == node) iter->next_node_ = succNode_(node);
795
796 if (iter->prev_node_ == node) iter->prev_node_ = prevNode_(node);
797
798 if (iter->parent_ == node) iter->parent_ = node->parent();
799
800 if (iter->left_child_ == node) iter->left_child_ = node->leftChild();
801
802 if (iter->right_child_ == node) iter->right_child_ = node->rightChild();
803 }
804 }
805 }
806
807} // namespace gum
808
809#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:76
gum is the global namespace for all aGrUM entities
Definition agrum.h:46