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