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