aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
splay_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 Template implementation of splay trees
25  *
26  * @author Karim Tekkal
27  */
28 #include <agrum/tools/core/splay.h>
29 
30 namespace gum {
31  /* =========================================================================*/
32  /* =========================================================================*/
33  /* === Implementation of gumSplayBinaryNode === */
34  /* =========================================================================*/
35  /* =========================================================================*/
36 
37  // a function used to perform copies of HashTableLists
38 
39  template < class Element >
40  INLINE void
43  if (addr.exists(from.elt))
44  addr[from.elt] = this;
45  else
46  addr.insert(from.elt, this);
47 
48  elt = from.elt;
49 
50  size = from.size;
51 
52  pere = 0;
53 
54  if (from.fg) {
55  fg = new SplayBinaryNode< Element >(*from.fg, addr);
56  fg->pere = this;
57  } else {
58  fg = 0;
59  }
60 
61  if (from.fd) {
62  fd = new SplayBinaryNode< Element >(*from.fd, addr);
63  fd->pere = this;
64  } else {
65  fd = 0;
66  }
67  }
68 
69  // constructor
70 
71  template < class Element >
73  const Element& e,
77  SplayBinaryNode* p) :
78  elt(e),
79  size(1), fg(g), fd(d), pere(p) {
80  if (addr.exists(elt))
81  addr[elt] = this;
82  else
83  addr.insert(elt, this);
84 
85  // for debugging purposes
87  }
88 
89  // copy operator
90 
91  template < class Element >
93  const SplayBinaryNode< Element >& from,
95  copy_(from, addr);
96  // for debugging purposes
98  }
99 
100  // destructor
101 
102  template < class Element >
104  // for debugging purposes
106  // remove the subtrees
107 
108  if (fg) delete fg;
109 
110  if (fd) delete fd;
111  }
112 
113  // Perform a right rotation, returns the node
114 
115  template < class Element >
117  Size size_;
118  // Must be called on a node with a father
119  GUM_ASSERT(pere != 0);
120  // We chain childs
121  pere->fg = fd;
122 
123  if (fd) fd->pere = pere;
124 
125  fd = pere;
126 
128 
129  fd->pere = this;
130 
131  // We compute the size of rigth child
132  size_ = 1;
133 
134  if (fd->fg) size_ += fd->fg->size;
135 
136  if (fd->fd) size_ += fd->fd->size;
137 
138  fd->size = size_;
139 
140  // size_ == fd->size
141  if (fg) size_ += fg->size;
142 
143  ++size_;
144 
145  size = size_;
146 
147  // We chain father
148  pere = p;
149 
150  if (pere) {
151  if (pere->fg == fd) {
152  // I'm left child of my father
153  pere->fg = this;
154  } else {
155  // I'm right child of my father
156  GUM_ASSERT(pere->fd == fd);
157  pere->fd = this;
158  }
159  }
160 
161  return this;
162  }
163 
164  // Perform a left rotation, returns the node
165 
166  template < class Element >
168  Size size_;
169  // Must be call on a node with a father
170  GUM_ASSERT(pere != 0);
171  // We chain childs
172  pere->fd = fg;
173 
174  if (fg) fg->pere = pere;
175 
176  fg = pere;
177 
179 
180  fg->pere = this;
181 
182  // We compute the size of rigth child
183  size_ = 1;
184 
185  if (fg->fg) size_ += fg->fg->size;
186 
187  if (fg->fd) size_ += fg->fd->size;
188 
189  fg->size = size_;
190 
191  if (fd) size_ += fd->size;
192 
193  ++size_;
194 
195  size = size_;
196 
197  // We chain father
198  pere = p;
199 
200  if (pere) {
201  if (pere->fg == fg) {
202  // I'm left child of my father
203  pere->fg = this;
204  } else {
205  // I'm right child of my father
206  GUM_ASSERT(pere->fd == fg);
207  pere->fd = this;
208  }
209  }
210 
211  return this;
212  }
213 
214  // Perform a splay rotation, the node return is the root
215 
216  template < class Element >
219 
220  while (pere) {
221  // While this node isn't the root
222  gdp = pere->pere; // gdp can be nullptr
223 
224  if (!gdp) {
225  if (this == pere->fg) {
226  // I'm the left child of my father
227  return zig();
228  } else {
229  GUM_ASSERT(this == pere->fd);
230  // I'm the right child of my father
231  return zag();
232  }
233  } else {
234  if (this == pere->fg) {
235  // I'm the left child of my father
236  if (pere == gdp->fg) {
237  gdp->fg = zig();
238  } else {
239  GUM_ASSERT(pere == gdp->fd);
240  gdp->fd = zig();
241  }
242  } else {
243  GUM_ASSERT(this == pere->fd);
244  // I'm the right child of my father
245 
246  if (pere == gdp->fg) {
247  gdp->fg = zag();
248  } else {
249  GUM_ASSERT(pere == gdp->fd);
250  gdp->fd = zag();
251  }
252  }
253  }
254  }
255 
256  return this; // for compiler satisfaction
257  }
258 
259  // Concatenation of two threes
260 
261  template < class Element >
266  GUM_ASSERT(b != 0);
267  SplayBinaryNode< Element >* act = this;
268 
269  for (; act->fd; act = act->fd)
270  ;
271 
272  // act is the rightmost element
273  act->splay();
274 
275  // insertion
276  act->fd = b;
277 
278  b->pere = act;
279 
280  act->size = 1;
281 
282  if (act->fg) act->size += act->fg->size;
283 
284  act->size += act->fd->size;
285 
286  return act;
287  }
288 
289  // Get the position of the node
290 
291  template < class Element >
293  if (!pere) {
294  // I'm the root
295  if (fg)
296  return fg->size + 1;
297  else
298  return 0;
299  } else if (pere->fg == this) {
300  // I'm the left child of my father
301  int pos = pere->position() - 1;
302 
303  if (fd) pos -= fd->size;
304 
305  return pos;
306  } else {
307  // I'm the right child of my father
308  int pos = pere->position() + 1;
309 
310  if (fg) pos += fg->size;
311 
312  return pos;
313  }
314  }
315 
316  // Get the element in the node
317 
318  template < class Element >
320  return elt;
321  }
322 
323  /*
324  * @return the left child
325  * @warning the returned value can be null
326  */
327 
328  template < class Element >
330  return fg;
331  }
332 
333  /*
334  * @return the right child
335  * @warning the returned value can be null
336  */
337 
338  template < class Element >
340  return fd;
341  }
342 
343  /* =========================================================================*/
344  /* =========================================================================*/
345  /* === Implementation of SplayTree === */
346  /* =========================================================================*/
347  /* =========================================================================*/
348 
349  // a function used to perform copies
350 
351  template < class Element >
353  if (from.root) {
355  } else {
356  root = 0;
357  }
358  }
359 
360  // basic constructor, make an empty splay tree
361 
362  template < class Element >
364  // for debugging purposes
366  }
367 
368  // basic constructor, make a splay tree with one element
369  /*
370  * @param e the element of the tree
371  */
372 
373  template < class Element >
375  root = new SplayBinaryNode< Element >(e, addr);
376  // for debugging purposes
378  }
379 
380  // copy constructor
381 
382  template < class Element >
384  copy_(from);
385  // for debugging purposes
387  }
388 
389  // Assignment operator
390 
391  template < class Element >
393  // avoid self assignment
394  if (this != &from) {
395  // for debugging purposes
397  // delete the old contents
398 
399  if (root) delete root;
400 
401  addr.clear();
402 
403  copy_(from);
404  }
405 
406  return *this;
407  }
408 
409  // Destructor
410 
411  template < class Element >
413  // for debugging purposes
415 
416  if (root) delete (root);
417  }
418 
419  // Get the element at the position n
420 
421  template < class Element >
422  Element& SplayTree< Element >::operator[](const unsigned int i) {
423  int val = i;
424 
425  if (!root) {
426  GUM_ERROR(NotFound, "The tree is empty !")
427  } else if (val >= root->size) {
428  GUM_ERROR(NotFound, "The index is too large !")
429  } else {
430  // The element exists
431  // Find it
433  int pos_act = val - 1;
434  bool next = true;
435 
436  while (next) {
437  if (!act->fg)
438  pos_act = 0;
439  else
440  pos_act = act->fg->size;
441 
442  if (pos_act > val) {
443  act = act->fg;
444  } else if (pos_act < val) {
445  act = act->fd;
446  val -= (pos_act + 1);
447  } else {
448  next = false;
449  }
450  }
451 
452  root = act->splay();
453 
454  return root->elt;
455  }
456  }
457 
458  template < class Element >
459  const Element& SplayTree< Element >::operator[](const unsigned int i) const {
460  int val = i;
461 
462  if (!root) {
463  GUM_ERROR(NotFound, "The tree is empty !")
464  } else if (val >= root->size) {
465  GUM_ERROR(NotFound, "The index is too large !")
466  } else {
467  // The element exists
468  // Find it
470  int pos_act = val - 1;
471  bool next = true;
472 
473  while (next) {
474  if (!act->fg)
475  pos_act = 0;
476  else
477  pos_act = act->fg->size;
478 
479  if (pos_act > val) {
480  act = act->fg;
481  } else if (pos_act < val) {
482  act = act->fd;
483  val -= (pos_act + 1);
484  } else {
485  next = false;
486  }
487  }
488 
489  root = act->splay();
490 
491  return root->elt;
492  }
493  }
494 
495  // Get the first element
496 
497  template < class Element >
500 
501  if (!root) { GUM_ERROR(NotFound, "The splay tree is empty") }
502 
503  if (act->fg)
504  for (; act->fg; act = act->fg)
505  ;
506 
507  root = act->splay();
508 
509  return root->elt;
510  }
511 
512  // Get the last element
513 
514  template < class Element >
517 
518  if (!root) { GUM_ERROR(NotFound, "The splay tree is empty") }
519 
520  if (act->fd)
521  for (; act->fd; act = act->fd)
522  ;
523 
524  root = act->splay();
525 
526  return root->elt;
527  }
528 
529  // Remove the first element
530 
531  template < class Element >
534 
535  if (root) {
536  if (root->fg)
537  for (; act->fg; act = act->fg)
538  ;
539 
540  act = act->splay();
541 
542  root = act->fd;
543 
544  if (root) root->pere = 0;
545 
546  act->fd = 0;
547 
548  delete act;
549  }
550  }
551 
552  // Remove the last element
553 
554  template < class Element >
557 
558  if (root) {
559  if (root->fd)
560  for (; act->fd; act = act->fd)
561  ;
562 
563  act = act->splay();
564 
565  root = act->fg;
566 
567  if (root) root->pere = 0;
568 
569  act->fg = 0;
570 
571  delete act;
572  }
573  }
574 
575  // Add an element in the first position
576 
577  template < class Element >
580 
581  if (root) {
582  if (root->fg)
583  for (; act->fg; act = act->fg)
584  ;
585 
586  root = act->splay();
587 
588  root->fg = new SplayBinaryNode< Element >(e, addr, 0, 0, root);
589  } else {
590  root = new SplayBinaryNode< Element >(e, addr);
591  }
592  }
593 
594  // Add an element in the last position
595 
596  template < class Element >
599 
600  if (root) {
601  if (root->fd)
602  for (; act->fd; act = act->fd)
603  ;
604 
605  root = act->splay();
606 
607  root->fd = new SplayBinaryNode< Element >(e, addr, 0, 0, root);
608  } else {
609  root = new SplayBinaryNode< Element >(e, addr);
610  }
611  }
612 
613  // Add an element to the tree
614 
615  template < class Element >
616  INLINE void SplayTree< Element >::insert(const Element& e) {
618 
619  if (!root) {
620  root = new SplayBinaryNode< Element >(e, addr);
621  } else {
622  while (act->fd) {
623  ++act->size;
624  act = act->fd;
625  }
626 
627  // act->fd == nullptr
628  act->fd = new SplayBinaryNode< Element >(e, addr, 0, 0, act);
629 
630  ++act->size;
631 
632  root = act->fd->splay();
633  }
634  }
635 
636  // Concatenation of two trees
637  /*
638  * @param s the tree to add
639  */
640 
641  template < class Element >
643  if (s.root) {
644  if (root) {
645  root = root->join(s.root, addr);
646  } else {
647  root = new SplayBinaryNode< Element >(*s.root, addr);
648  }
649  }
650  }
651 
652  // removeInfo removes all the information about the nodes contains by e
653 
654  template < class Element >
655  INLINE static void removeInfo(const SplayBinaryNode< Element >* e,
658  addr.erase(e->getElement());
659 
660  if (e->getFg()) removeInfo(e->getFg(), addr);
661 
662  if (e->getFd()) removeInfo(e->getFd(), addr);
663  }
664 
665  // Split the tree at the element
666 
667  template < class Element >
669  GUM_ASSERT(i >= 0 && i < root->size);
670  GUM_ASSERT(root != 0);
671 
672  if (i == 0) {
673  // the tree will be empty
674  // the returned tree is a copy of the present tree
675  SplayTree< Element > s = *this;
676  addr.clear();
677  delete root;
678  root = 0;
679  return s;
680  } else if (i == root->size - 1) {
681  SplayTree< Element > s;
682  return s;
683  } else {
684  // We will find the node at position i
686  int pos = root->position();
687 
688  while (pos != i) {
689  GUM_ASSERT(act != 0);
690 
691  if (i < pos) {
692  act = act->fg;
693  } else {
694  act = act->fd;
695  }
696 
697  pos = act->position();
698  }
699 
700  // We reorganize the tree
701  act->splay();
702 
703  // We take the first part
704  root = act->fg;
705 
706  if (root) root->pere = 0;
707 
708  // We take the second part
709  SplayTree< Element > s;
710 
711  s.root = act;
712 
713  s.root->fg = 0;
714 
715  Size size_ = 1;
716 
717  if (s.root->fd) size_ += s.root->fd->size;
718 
719  s.root->size = size_;
720 
721  // We remove the old nodes in the hash table
722  // Complexity O(n) => very expensive
723  removeInfo(act, addr);
724 
725  return s;
726  }
727  }
728 
729  // Split the tree at the element
730 
731  template < typename Element >
733  GUM_ASSERT(root != 0);
734 
735  if (!addr.exists(e)) { GUM_ERROR(NotFound, "not enough elements in the splay tree") }
736 
737  // We will find the node at position i
739 
740  // We reorganize the tree
741  act->splay();
742 
743  // We take the two parts
744  SplayTree< Element > s;
745 
746  s.root = act->fd;
747 
748  if (s.root) { s.root->pere = 0; }
749 
750  root = act->fg;
751 
752  if (root) root->pere = 0;
753 
754  act->fg = 0;
755 
756  // We remove the old nodes in the hash table
757  // Complexity O(n) => very expensive
758  removeInfo(act, addr);
759 
760  act->fd = 0;
761 
762  delete act;
763 
764  return s;
765  }
766 
767  // The number of elements in the tree
768 
769  template < class Element >
771  if (root)
772  return root->size;
773  else
774  return Size(0);
775  }
776 
777  // Test if the tree contains the element
778 
779  template < class Element >
780  INLINE bool SplayTree< Element >::contains(const Element& e) const {
781  return addr.exists(e);
782  }
783 
784  // Display the node
785 
786  template < typename Element >
788  if (e.fg) out << *e.fg << ",";
789 
790  out << e.elt;
791 
792  if (e.fd) out << "," << *e.fd;
793 
794  return out;
795  }
796 
797  // Display the tree
798 
799  template < typename Element >
801  out << "|[";
802 
803  if (s.root) out << *s.root;
804 
805  out << "]|";
806 
807  return out;
808  }
809 
810 } /* namespace gum */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643