aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
splay_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 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 >
41  const SplayBinaryNode< Element >& from,
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 >
263  const SplayBinaryNode< Element >* e,
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 >
329  INLINE const SplayBinaryNode< Element >*
331  return fg;
332  }
333 
334  /*
335  * @return the right child
336  * @warning the returned value can be null
337  */
338 
339  template < class Element >
340  INLINE const SplayBinaryNode< Element >*
342  return fd;
343  }
344 
345  /* =========================================================================*/
346  /* =========================================================================*/
347  /* === Implementation of SplayTree === */
348  /* =========================================================================*/
349  /* =========================================================================*/
350 
351  // a function used to perform copies
352 
353  template < class Element >
355  if (from.root) {
357  } else {
358  root = 0;
359  }
360  }
361 
362  // basic constructor, make an empty splay tree
363 
364  template < class Element >
366  // for debugging purposes
368  }
369 
370  // basic constructor, make a splay tree with one element
371  /*
372  * @param e the element of the tree
373  */
374 
375  template < class Element >
377  root = new SplayBinaryNode< Element >(e, addr);
378  // for debugging purposes
380  }
381 
382  // copy constructor
383 
384  template < class Element >
386  copy_(from);
387  // for debugging purposes
389  }
390 
391  // Assignment operator
392 
393  template < class Element >
396  // avoid self assignment
397  if (this != &from) {
398  // for debugging purposes
400  // delete the old contents
401 
402  if (root) delete root;
403 
404  addr.clear();
405 
406  copy_(from);
407  }
408 
409  return *this;
410  }
411 
412  // Destructor
413 
414  template < class Element >
416  // for debugging purposes
418 
419  if (root) delete (root);
420  }
421 
422  // Get the element at the position n
423 
424  template < class Element >
425  Element& SplayTree< Element >::operator[](const unsigned int i) {
426  int val = i;
427 
428  if (!root) {
429  GUM_ERROR(NotFound, "The tree is empty !");
430  } else if (val >= root->size) {
431  GUM_ERROR(NotFound, "The index is too large !");
432  } else {
433  // The element exists
434  // Find it
436  int pos_act = val - 1;
437  bool next = true;
438 
439  while (next) {
440  if (!act->fg)
441  pos_act = 0;
442  else
443  pos_act = act->fg->size;
444 
445  if (pos_act > val) {
446  act = act->fg;
447  } else if (pos_act < val) {
448  act = act->fd;
449  val -= (pos_act + 1);
450  } else {
451  next = false;
452  }
453  }
454 
455  root = act->splay();
456 
457  return root->elt;
458  }
459  }
460 
461  template < class Element >
462  const Element& SplayTree< Element >::operator[](const unsigned int i) const {
463  int val = i;
464 
465  if (!root) {
466  GUM_ERROR(NotFound, "The tree is empty !");
467  } else if (val >= root->size) {
468  GUM_ERROR(NotFound, "The index is too large !");
469  } else {
470  // The element exists
471  // Find it
473  int pos_act = val - 1;
474  bool next = true;
475 
476  while (next) {
477  if (!act->fg)
478  pos_act = 0;
479  else
480  pos_act = act->fg->size;
481 
482  if (pos_act > val) {
483  act = act->fg;
484  } else if (pos_act < val) {
485  act = act->fd;
486  val -= (pos_act + 1);
487  } else {
488  next = false;
489  }
490  }
491 
492  root = act->splay();
493 
494  return root->elt;
495  }
496  }
497 
498  // Get the first element
499 
500  template < class Element >
503 
504  if (!root) { GUM_ERROR(NotFound, "The splay tree is empty"); }
505 
506  if (act->fg)
507  for (; act->fg; act = act->fg)
508  ;
509 
510  root = act->splay();
511 
512  return root->elt;
513  }
514 
515  // Get the last element
516 
517  template < class Element >
520 
521  if (!root) { GUM_ERROR(NotFound, "The splay tree is empty"); }
522 
523  if (act->fd)
524  for (; act->fd; act = act->fd)
525  ;
526 
527  root = act->splay();
528 
529  return root->elt;
530  }
531 
532  // Remove the first element
533 
534  template < class Element >
537 
538  if (root) {
539  if (root->fg)
540  for (; act->fg; act = act->fg)
541  ;
542 
543  act = act->splay();
544 
545  root = act->fd;
546 
547  if (root) root->pere = 0;
548 
549  act->fd = 0;
550 
551  delete act;
552  }
553  }
554 
555  // Remove the last element
556 
557  template < class Element >
560 
561  if (root) {
562  if (root->fd)
563  for (; act->fd; act = act->fd)
564  ;
565 
566  act = act->splay();
567 
568  root = act->fg;
569 
570  if (root) root->pere = 0;
571 
572  act->fg = 0;
573 
574  delete act;
575  }
576  }
577 
578  // Add an element in the first position
579 
580  template < class Element >
583 
584  if (root) {
585  if (root->fg)
586  for (; act->fg; act = act->fg)
587  ;
588 
589  root = act->splay();
590 
591  root->fg = new SplayBinaryNode< Element >(e, addr, 0, 0, root);
592  } else {
593  root = new SplayBinaryNode< Element >(e, addr);
594  }
595  }
596 
597  // Add an element in the last position
598 
599  template < class Element >
602 
603  if (root) {
604  if (root->fd)
605  for (; act->fd; act = act->fd)
606  ;
607 
608  root = act->splay();
609 
610  root->fd = new SplayBinaryNode< Element >(e, addr, 0, 0, root);
611  } else {
612  root = new SplayBinaryNode< Element >(e, addr);
613  }
614  }
615 
616  // Add an element to the tree
617 
618  template < class Element >
619  INLINE void SplayTree< Element >::insert(const Element& e) {
621 
622  if (!root) {
623  root = new SplayBinaryNode< Element >(e, addr);
624  } else {
625  while (act->fd) {
626  ++act->size;
627  act = act->fd;
628  }
629 
630  // act->fd == nullptr
631  act->fd = new SplayBinaryNode< Element >(e, addr, 0, 0, act);
632 
633  ++act->size;
634 
635  root = act->fd->splay();
636  }
637  }
638 
639  // Concatenation of two trees
640  /*
641  * @param s the tree to add
642  */
643 
644  template < class Element >
646  if (s.root) {
647  if (root) {
648  root = root->join(s.root, addr);
649  } else {
650  root = new SplayBinaryNode< Element >(*s.root, addr);
651  }
652  }
653  }
654 
655  // removeInfo removes all the information about the nodes contains by e
656 
657  template < class Element >
658  INLINE static void
662  addr.erase(e->getElement());
663 
664  if (e->getFg()) removeInfo(e->getFg(), addr);
665 
666  if (e->getFd()) removeInfo(e->getFd(), addr);
667  }
668 
669  // Split the tree at the element
670 
671  template < class Element >
673  GUM_ASSERT(i >= 0 && i < root->size);
674  GUM_ASSERT(root != 0);
675 
676  if (i == 0) {
677  // the tree will be empty
678  // the returned tree is a copy of the present tree
679  SplayTree< Element > s = *this;
680  addr.clear();
681  delete root;
682  root = 0;
683  return s;
684  } else if (i == root->size - 1) {
685  SplayTree< Element > s;
686  return s;
687  } else {
688  // We will find the node at position i
690  int pos = root->position();
691 
692  while (pos != i) {
693  GUM_ASSERT(act != 0);
694 
695  if (i < pos) {
696  act = act->fg;
697  } else {
698  act = act->fd;
699  }
700 
701  pos = act->position();
702  }
703 
704  // We reorganize the tree
705  act->splay();
706 
707  // We take the first part
708  root = act->fg;
709 
710  if (root) root->pere = 0;
711 
712  // We take the second part
713  SplayTree< Element > s;
714 
715  s.root = act;
716 
717  s.root->fg = 0;
718 
719  Size size_ = 1;
720 
721  if (s.root->fd) size_ += s.root->fd->size;
722 
723  s.root->size = size_;
724 
725  // We remove the old nodes in the hash table
726  // Complexity O(n) => very expensive
727  removeInfo(act, addr);
728 
729  return s;
730  }
731  }
732 
733  // Split the tree at the element
734 
735  template < typename Element >
738  GUM_ASSERT(root != 0);
739 
740  if (!addr.exists(e)) {
741  GUM_ERROR(NotFound, "not enough elements in the splay tree");
742  }
743 
744  // We will find the node at position i
746 
747  // We reorganize the tree
748  act->splay();
749 
750  // We take the two parts
751  SplayTree< Element > s;
752 
753  s.root = act->fd;
754 
755  if (s.root) { s.root->pere = 0; }
756 
757  root = act->fg;
758 
759  if (root) root->pere = 0;
760 
761  act->fg = 0;
762 
763  // We remove the old nodes in the hash table
764  // Complexity O(n) => very expensive
765  removeInfo(act, addr);
766 
767  act->fd = 0;
768 
769  delete act;
770 
771  return s;
772  }
773 
774  // The number of elements in the tree
775 
776  template < class Element >
778  if (root)
779  return root->size;
780  else
781  return Size(0);
782  }
783 
784  // Test if the tree contains the element
785 
786  template < class Element >
787  INLINE bool SplayTree< Element >::contains(const Element& e) const {
788  return addr.exists(e);
789  }
790 
791  // Display the node
792 
793  template < typename Element >
795  const SplayBinaryNode< Element >& e) {
796  if (e.fg) out << *e.fg << ",";
797 
798  out << e.elt;
799 
800  if (e.fd) out << "," << *e.fd;
801 
802  return out;
803  }
804 
805  // Display the tree
806 
807  template < typename Element >
809  const SplayTree< Element >& s) {
810  out << "|[";
811 
812  if (s.root) out << *s.root;
813 
814  out << "]|";
815 
816  return out;
817  }
818 
819 } /* namespace gum */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669