Aleph-w  1.5a.2
Biblioteca general de algoritmos y estructuras de datos
 Todo Clases Archivos Funciones Variables 'typedefs' Enumeraciones Amigas Grupos Páginas
tpl_hRbTree.H
1 
2 /*
3  Hybrid Top down and botton up red black trees
4 */
5 
6 # ifndef TPL_HTDRBTREE_H
7 # define TPL_HTDRBTREE_H
8 
9 # ifdef DEBUG
10 # include <math.h>
11 # endif
12 # include <tpl_binNode.H>
13 # include <tpl_binNodeUtils.H>
14 # include <tpl_arrayStack.H>
15 # include <rbNode.H>
16 
17 # define COLOR(p) (p->getColor())
18 
19 using namespace BinNode_Utils;
20 
21  template <class Key>
22 class HtdRbTree
23 {
24 public:
25 
26  typedef unsigned char Color;
27 
28 private:
29 
30  /*
31  Node definition of a red black tree.
32 
33  It's a binary node (BinNode<Key>) with an attribute called color.
34  It uses a *BLACK* sentinel node for null nodes (Node::NullPtr)
35  */
36  friend class _Node : public BinNode<Key>
37  {
38  private:
39  friend class HtdRbTree<Key>;
40 
41  Color color; // color is either BLACK or RED
42 
43  static const _Node<Key> nodeSentinel;
44 
46  _Node(EmptyCtor)
47  : BinNode<Key>(emptyCtor), color(BLACK)
48  {
49  getL() = _Node<Key>::Node::NullPtr;
50  getR() = _Node<Key>::Node::NullPtr;
51  }
52 
53  public:
54 
56  static const unsigned int MaxHeight = 128;
57  static _Node<Key> * const Node::NullPtr
58  = const_cast<_Node<Key>*>(&nodeSentinel);
59 
60  _Node(Color c = RED)
61  : BinNode<Key>(emptyCtor), color(c)
62  {
63  getL() = _Node<Key>::Node::NullPtr;
64  getR() = _Node<Key>::Node::NullPtr;
65  }
66 
67  _Node(const Key& _key)
68  : BinNode<Key>(emptyCtor), color(RED)
69  {
70  get_key() = _key;
71  getL() = _Node<Key>::Node::NullPtr;
72  getR() = _Node<Key>::Node::NullPtr;
73  }
74 
75  Color& getColor() { return color; }
76 
77  Color getColor() const { return color; }
78  }; // end of _Node
79 
80 public:
81 
82  typedef MetaBinNode<_Node, Key> Node;
83 
84 private:
85 
86  static Node * const Node::NullPtr = Node::Node::NullPtr;
87 
89  Node headNode;
90 
92  Node headParent;
93 
95  Node headGrandParent;
96 
98  Node *head;
99 
100  Node *fHead;
101 
102  Node *ffHead;
103 
105  Node *&root;
106 
108  FixedStack<Node*> path(Node::MaxHeight);
109 
110 # ifdef DEBUG
111 
115  unsigned int n;
116 # endif /* DEBUG */
117 
125  Node* getSibling(Node *p, Node *fp)
126  {
127  I(LLINK(fp) == p || RLINK(fp) == p);
128  return LLINK(fp) == p ? RLINK(fp) : LLINK(fp);
129  }
130 
131 
132  /* Routines exclusively used by insertion procedure */
133 
152  void restoreRedCondition(Node *p,
153  Node *&fp,
154  Node *ffp,
155  Node *fffp)
156  {
157  /* Sanity checks */
158  I(LLINK(fp) == p || RLINK(fp) == p);
159  I(COLOR(fp) == RED);
160  I(COLOR(p) == RED);
161 
162  if (fp == root)
163  {
164  COLOR(fp) = BLACK;
165  return;
166  }
167 
168  I(LLINK(ffp) == fp || RLINK(ffp) == fp);
169  I(COLOR(ffp) == BLACK);
170  I(LLINK(fffp) == ffp || RLINK(fffp) == ffp);
171 
172  COLOR(ffp) = RED;
173 
174  if (LLINK(fp) == p && LLINK(ffp) == fp)
175  {
176  COLOR(fp) = BLACK;
177  rotate_to_right(ffp, fffp);
178  }
179  else if (RLINK(fp) == p && RLINK(ffp) == fp)
180  {
181  COLOR(fp) = BLACK;
182  rotate_to_left(ffp, fffp);
183  }
184  else
185  {
186  COLOR(p) = BLACK;
187  if (RLINK(fp) == p)
188  {
189  rotate_to_left(fp, ffp);
190  rotate_to_right(ffp, fffp);
191  }
192  else
193  {
194  rotate_to_right(fp, ffp);
195  rotate_to_left(ffp, fffp);
196  }
197  fp = fffp;
198  }
199  }
200 
209  static void flipColors(Node* p)
210  {
211  I(p != Node::NullPtr);
212  I(COLOR(p) == BLACK);
213  I(COLOR(LLINK(p)) == RED && COLOR(RLINK(p)) == RED);
214 
215  COLOR(p) = RED;
216  COLOR(LLINK(p)) = COLOR(RLINK(p)) = BLACK;
217  }
218 
227  Node* searchFlipColorsAndInsert(Node *q)
228  {
229  I(q != Node::NullPtr);
230  I(root != Node::NullPtr);
231  I(COLOR(q) == RED);
232  I(LLINK(q) == Node::NullPtr && RLINK(q) == Node::NullPtr);
233 
234  Node *p = root; // Current node
235  Node *fp = head; // p's parent
236  Node *ffp = fHead; // p's grand parent
237  Node *fffp = ffHead; // p's great grand parent
238  Node *nextNode;
239 
240  while (1)
241  {
242  if (KEY(q) == KEY(p))
243  return NULL; /* Duplicated key, insertion is not possible */
244 
245  if (COLOR(p) == BLACK && COLOR(LLINK(p)) == RED
246  && COLOR(RLINK(p)) == RED)
247  {
248  flipColors(p); // Rends p red
249  if (COLOR(fp) == RED) // violation of red condition
250  {
251  I(fffp != Node::NullPtr);
252  restoreRedCondition(p, fp, ffp, fffp);
253  }
254  }
255 
256  if (KEY(q) < KEY(p))
257  {
258  if (LLINK(p) == Node::NullPtr)
259  break;
260  nextNode = LLINK(p);
261  }
262  else
263  {
264  if (RLINK(p) == Node::NullPtr)
265  break;
266  nextNode = RLINK(p);
267  }
268 
269  fffp = ffp;
270  ffp = fp;
271  fp = p;
272  p = nextNode;
273  }
274 
275 # ifdef DEBUG
276  n++;
277 # endif
278 
279  /* Insertion act */
280  if (KEY(q) < KEY(p))
281  LLINK(p) = q;
282 
283  else
284  RLINK(p) = q;
285 
286  if (COLOR(p) == RED) // Violation of red condition
287  restoreRedCondition(q, p, fp, ffp);
288 
289  return q;
290  }
291 
292  /* The following routines are exclusively used by remove procedure */
293 
301  Node* searchAndBuildPath(const Key& key)
302  {
303  I(root != Node::NullPtr);
304 
305  Node *p = root;
306  path.push(head);
307 
308  while (1)
309  {
310  path.push(p);
311 
312  if (key == KEY(p))
313  {
314  I(path.getLen() - 1.0 <= 2*log(n + 1)/log(2));
315  return p;
316  }
317 
318  if (key < KEY(p))
319  {
320  if (LLINK(p) == Node::NullPtr)
321  {
322  I(path.getLen() - 1.0 <= 2*log(n + 1)/log(2));
323  return p;
324  }
325 
326  p = LLINK(p);
327  continue;
328  }
329 
330  if (RLINK(p) == Node::NullPtr)
331  {
332  I(path.getLen() - 1.0 <= 2*log(n + 1)/log(2));
333  return p;
334  }
335 
336  p = RLINK(p);
337  }
338  }
339 
350  void findSuccAndSwap(Node *p, Node *&fp)
351  {
352  I(p != Node::NullPtr);
353  I(RLINK(p) != Node::NullPtr);
354  I(fp != Node::NullPtr);
355  I(LLINK(fp) == p || RLINK(fp) == p);
356 
357  /*
358  We save a reference to current stack content because p will be
359  swapped and p's position in stack should be occupied by
360  successor of p
361  */
362  Node *&refToSearchPath = path.lookAt();
363 
364  I(refToSearchPath == p);
365 
366  /* Find succesor while updating searchPath */
367  Node *fSucc = p; // succesor's parent
368  Node *succ = RLINK(p); // Searching starts from p's right child
369 
370  path.push(succ);
371  while (LLINK(succ) != Node::NullPtr) // go down to leftmost
372  {
373  fSucc = succ;
374  succ = LLINK(succ);
375  path.push(succ);
376  }
377  I(path.getLen() - 1.0 <= 2*log(n + 1)/log(2));
378 
379  /*
380  update old stack entry occupied by p These operations are
381  equivalents to swap old top with current top
382  */
383  refToSearchPath = succ;
384  path.lookAt() = p;
385 
386  /* Setting of parent of p to its new child (succ) */
387  if (LLINK(fp) == p)
388  LLINK(fp) = succ;
389  else
390  RLINK(fp) = succ;
391 
392  /* Swaps left branches */
393  LLINK(succ) = LLINK(p);
394  LLINK(p) = Node::NullPtr;
395 
396  /* For right branches there are two cases */
397  if (RLINK(p) == succ)
398  { /* successor is just right's child of p */
399  RLINK(p) = RLINK(succ);
400  RLINK(succ) = p;
401  fp = succ;
402  }
403  else
404  { /*
405  successor is the leftmost nodo descending from right child of p
406  */
407  Node *succr = RLINK(succ);
408  RLINK(succ) = RLINK(p);
409  LLINK(fSucc) = p;
410  RLINK(p) = succr;
411  fp = fSucc;
412  }
413 
414  // Swap of colors
415  Color tmp = COLOR(succ);
416  COLOR(succ) = COLOR(p);
417  COLOR(p) = tmp;
418  }
419 
420 
444  void balanceDownAndColor(Node *p, Node *&fp, Node *&sp)
445  {
446  I(LLINK(fp) == p || RLINK(fp) == p);
447  I(LLINK(fp) == sp || RLINK(fp) == sp);
448  I(COLOR(fp) == BLACK);
449  I(COLOR(sp) == RED);
450  I(COLOR(p) == BLACK);
451  I(!path.is_empty());
452 
453  /* needed by rotation for links' update. We save a reference to search
454  stack because stack's head will cahnge after rotation */
455  Node *&ffp = path.lookAt();
456 
457  I(LLINK(ffp) == fp || RLINK(ffp) == fp);
458 
459  ID(Node *oldSp = sp); // Saves for futur verification
460  /* balancing down of p, update of out parameters and update of stack
461  entry corresponding to fp */
462  if (LLINK(fp) == p)
463  {
464  sp = LLINK(sp);
465  ffp = rotate_to_left(fp, ffp);
466  }
467  else
468  {
469  sp = RLINK(sp);
470  ffp = rotate_to_right(fp, ffp);
471  }
472 
473  I(LLINK(fp) == sp || RLINK(fp) == sp);
474  I(COLOR(ffp) == RED);
475  I(ffp == oldSp);
476 
477  /* coloring for ensuring to apply sibling black cases */
478  COLOR(ffp) = BLACK;
479  COLOR(fp) = RED;
480  }
481 
503  void rotateNephewAndColor(Node *fp, Node *sp, Node* np)
504  {
505  I(LLINK(fp) == sp || RLINK(fp) == sp);
506  I(LLINK(sp) == np || RLINK(sp) == np);
507  I(COLOR(sp) == BLACK);
508  I(COLOR(np) == RED);
509  I(!path.is_empty());
510 
511  Node *ffp = path.lookAt();
512 
513  I(LLINK(ffp) == fp || RLINK(ffp) == fp);
514 
515  /* rotation for downing low fp */
516  if (RLINK(sp) == np)
517  rotate_to_left(fp, ffp);
518  else
519  rotate_to_right(fp, ffp);
520 
521  /* coloring for fixing up red black conditions */
522  COLOR(sp) = COLOR(fp);
523  COLOR(fp) = BLACK;
524  COLOR(np) = BLACK;
525  }
526 
549  void doubleRotateNephewAndColor(Node *fp, Node *sp, Node *snp)
550  {
551  I(LLINK(fp) == sp || RLINK(fp) == sp);
552  I(LLINK(sp) == snp || RLINK(sp) == snp);
553  I(COLOR(sp) == BLACK);
554  I(COLOR(snp) == RED);
555  I(!path.is_empty());
556 
557  Node *ffp = path.lookAt();
558 
559  I(LLINK(ffp) == fp || RLINK(ffp) == fp);
560 
561  /* double rotation for raising up of snp. snp becomes the new root of
562  sub tree fp */
563  if (LLINK(sp) == snp)
564  {
565  rotate_to_right(sp, fp);
566  rotate_to_left(fp, ffp);
567  }
568  else
569  {
570  rotate_to_left(sp, fp);
571  rotate_to_right(fp, ffp);
572  }
573 
574  /* coloring for restoring all red black tree conditions */
575  COLOR(snp) = COLOR(fp);
576  COLOR(fp) = BLACK;
577  }
578 
586  static void colorSiblingAsRed(Node *sp)
587  {
588  I(COLOR(sp) == BLACK);
589  COLOR(sp) = RED;
590  }
591 
600  static void colorParentAndSibling(Node *fp, Node *sp)
601  {
602  I(LLINK(fp) == sp || RLINK(fp) == sp);
603  I(COLOR(fp) == RED);
604  I(COLOR(sp) == BLACK);
605 
606  COLOR(fp) = BLACK;
607  COLOR(sp) = RED;
608  }
609 
618 void removeAndFixBlackCondition(Node* q)
619  {
620  I(path.lookAt() == q);
621 
622  /* look at second item after stack's head. We cannot it pop because
623  succesor finding would require stack pushing */
624  Node* fq = path.lookAt(1);
625  Node *p; /* Saves the new child of fp after p has been deleted, this
626  node can be a violating black condition black node */
627 
628  I(fq != Node::NullPtr);
629  I( LLINK(fq) == q || RLINK(fq) == q);
630 
631  /* Deletion step: by pass if there is a Node::NullPtr link or swap
632  with successor */
633  ID(int itCount = 0); // iterations's counter
634  while (1)
635  {
636  IS(itCount++);
637  if (LLINK(q) == Node::NullPtr) // by pass to the left side
638  {
639  if (LLINK(fq) == q)
640  p = LLINK(fq) = RLINK(q);
641  else
642  p = RLINK(fq) = RLINK(q);
643  break;
644  }
645 
646  if (RLINK(q) == Node::NullPtr) // by pass to the right side
647  {
648  if (LLINK(fq) == q)
649  p = LLINK(fq) = LLINK(q);
650  else
651  p = RLINK(fq) = LLINK(q);
652  break;
653  }
654 
655  findSuccAndSwap(q, fq);
656  }
657  I(itCount <= 2); // Maximum two iteration of previous while
658 
659  /* if color of deleted node is red, then all red black conditions are
660  met and adjust is not necessary */
661  if (COLOR(q) == RED)
662  {
663  I(COLOR(p) == BLACK);
664  path.empty();
665  return;
666  }
667 
668  /* if color of p is black, then it misses a black node and four condition
669  is violated. However, if p's child is red we can recoloring it black
670  for restoring the missing black node */
671  if (COLOR(p) == RED)
672  {
673  COLOR(p) = BLACK;
674  path.empty();
675  return;
676  }
677 
678  /* Bad luck we must do recoloring and/or balancing for restoring the
679  four condition */
680  Node *sp; // p's sibling
681  Node *np, *snp; // p's nephew and nephewg's sibling
682  Node *fp = fq; // we process in function of p
683 
684  path.pop(2); // pops deleted node and fp
685 
686  /* we examine p and we restore red black properties */
687  while (1)
688  {
689  if (p == root)
690  break;
691 
692  sp = getSibling(p, fp);
693 
694  /* if sibling is red, we rotate down for assuring that p' sibling
695  to be black */
696  if (COLOR(sp) == RED)
697  balanceDownAndColor(p, fp, sp);
698 
699  I(COLOR(sp) == BLACK);
700 
701  /* Compute nephews */
702  if (LLINK(fp) == p)
703  {
704  np = RLINK(sp);
705  snp = LLINK(sp);
706  }
707  else
708  {
709  np = LLINK(sp);
710  snp = RLINK(sp);
711  }
712 
713  if (COLOR(np) == RED)
714  {
715  rotateNephewAndColor(fp, sp, np);
716  break;
717  }
718 
719  if (COLOR(snp) == RED)
720  {
721  doubleRotateNephewAndColor(fp, sp, snp);
722  break;
723  }
724 
725  if (COLOR(fp) == RED)
726  {
727  colorParentAndSibling(fp, sp);
728  break;
729  }
730 
731  /* color and restart process with fp */
732  colorSiblingAsRed(sp);
733  p = fp;
734  fp = path.pop(); // colorSiblingAsRed(sp) does not pop it
735  }
736  path.empty();
737  }
738 
739 public:
740 
743  : head(&headNode),
744  fHead(&headParent),
745  ffHead(&headGrandParent),
746  root(headNode.getR())
747  {
748  RLINK(fHead) = head;
749  RLINK(ffHead) = fHead;
750  COLOR(Node::NullPtr) = BLACK;
751  COLOR(head) = BLACK;
752  COLOR(fHead) = BLACK;
753  COLOR(ffHead) = BLACK;
754 
755 # ifdef DEBUG
756  n = 0;
757 # endif /* DEBUG */
758  }
759 
761  virtual ~HtdRbTree()
762  {
763  // Empty
764  }
765 
773  Node* insert(Node *p)
774  {
775  I(p != Node::NullPtr);
776  I(COLOR(p) == RED);
777  I(LLINK(p) == Node::NullPtr && RLINK(p) == Node::NullPtr);
778 
779  if (root == Node::NullPtr)
780  {
781  root = p;
782 # ifdef DEBUG
783  n++;
784 # endif
785  return p;
786  }
787 
788  return searchFlipColorsAndInsert(p);
789  }
790 
798  Node* search(const Key& key)
799  {
800  Node* retVal = searchInBinTree(root, key);
801 
802  return retVal == Node::NullPtr ? NULL : retVal;
803  }
804 
805  /*
806  Remove a key from a HtdRbTree.
807 
808  Searches a key in a Rbltree and remove the containing the key if this
809  is found.
810 
811  @return a pointer to node containing the removed key.
812  @param key to search
813  */
814  Node* remove(const Key& key)
815  {
816  if (root == Node::NullPtr)
817  return NULL;
818 
819  Node *p = searchAndBuildPath(key);
820 
821  if (KEY(p) != key)
822  {
823  path.empty();
824  return NULL;
825  }
826 
827  removeAndFixBlackCondition(p);
828 
829 # ifdef DEBUG
830  n++;
831 # endif
832 
833  return p;
834  }
835 
836 
838  Node*& getRoot() { return root; }
839 
840 private:
841 
855  static void blackHeight(Node *p, int &max, int bh = 0)
856  {
857  if (COLOR(p) == BLACK)
858  bh++; // Another seen black node
859 
860  /* if a leaf is reached, we must verify max with current bh (number of
861  visited black nodes */
862  if (LLINK(p) == Node::NullPtr && RLINK(p) == Node::NullPtr)
863  {
864  if (max == -1) // This is onbly for the first leaf reached
865  max = bh;
866  I(bh == max);
867  return;
868  }
869 
870  if (LLINK(p) != Node::NullPtr) /* continue counting in the left side */
871  blackHeight(LLINK(p), max, bh);
872 
873  if (RLINK(p) != Node::NullPtr) /* continue counting in the right side */
874  blackHeight(RLINK(p), max, bh);
875  }
876 
881  static void testNode(Node* p)
882  {
883  /* verify red condition */
884  COND_I(COLOR(p) == RED,
885  COLOR(LLINK(p)) == BLACK && COLOR(RLINK(p)) == BLACK);
886 
887  int max = -1;
888  int bh = 0;
889 
890  blackHeight(p, max, bh);
891  }
892 
893 public:
894 
904  {
905  /* traverse all tree and verify black height for each visited node */
906  preOrderRec(root, testNode);
907  }
908 };
909 
910 
911 template <class Key>
913 
914 
915 # undef COLOR
916 # undef RED
917 # undef BLACK
918 
919 #endif /* TPL_HTDRBTREE_H */
920 
921 
922 
923 
Node * rotate_to_left(Node *p)
Definition: tpl_binNodeUtils.H:2422
#define LLINK(p)
Definition: tpl_binNode.H:196
Node * insert(Node *p)
Definition: tpl_hRbTree.H:773
HtdRbTree()
Constructor.
Definition: tpl_hRbTree.H:742
#define RLINK(p)
Definition: tpl_binNode.H:201
Definition: tpl_hRbTree.H:22
Node * rotate_to_right(Node *p)
Definition: tpl_binNodeUtils.H:2375
Node * search(const Key &key)
Definition: tpl_hRbTree.H:798
Node * searchInBinTree(Node *root, const typename Node::key_type &key, Compare &cmp)
Definition: tpl_binNodeUtils.H:1728
static const unsigned int MaxHeight
Estimated for 4 Gb of nodes of 1 byte (according to 2*lg(n+1) bound)
Definition: tpl_hRbTree.H:56
int preOrderRec(Node *root, void(*visitFct)(Node *, int, int))
Definition: tpl_binNodeUtils.H:93
void verifyRedBlack()
Definition: tpl_hRbTree.H:903
Nodo binario básico.
virtual ~HtdRbTree()
Destructor.
Definition: tpl_hRbTree.H:761
Node *& getRoot()
Gets HtdRbTree's root.
Definition: tpl_hRbTree.H:838
#define KEY(p)
Definition: tpl_binNode.H:206

Leandro Rabindranath León