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