KrisLibrary  1.0.0
RedBlack.h
1 #ifndef REDBLACK_H
2 #define REDBLACK_H
3 
4 #include <KrisLibrary/Logger.h>
5 #include <iostream>
6 #include <assert.h>
7 #include <KrisLibrary/utils/cmp_func.h>
8 
9 namespace RedBlack {
10 
11 enum Color { Black, Red };
12 //defines the match type for the lookup function
13 enum Lookup { None, Equal,GTEQ,LTEQ,Less,Greater,Next,Prev};
14 
15 template <class T>
16 struct WalkCallback {
17  enum Visit { PreOrder, PostOrder, EndOrder, Leaf };
18  virtual ~WalkCallback() {}
19  virtual void Visit(const T& key, Visit visit, int level) {}
20 };
21 
22 template <class T>
23 class Node
24 {
25 public:
26  typedef Node<T> MyT;
27 
28  Node();
29  Node(const T&);
30  ~Node();
31  void detatch();
32  bool isValid() const;
33  int count_black();
34  void dumptree(std::ostream& out,int n);
35  MyT* successor() const; //Return a pointer to the smallest key greater than x
36  MyT* predecessor() const; //Return a pointer to the largest key less than x
37  void walk(WalkCallback<T>& callback,int level);
38  inline void setColor(Color c) { if(this==NULL) assert(c==Black); else color=c; }
39  inline Color getColor() const { if(this==NULL) return Black; return color; }
40  inline bool hasColor(Color c) const { return c==getColor(); }
41 
42  MyT *left; /* Left down */
43  MyT *right; /* Right down */
44  MyT *up; /* Up */
45  T key;
46 
47 private:
48  Color color;
49 };
50 
51 template <class T,class Cmp=std::cmp_func<T> >
52 class Tree
53 {
54 public:
55  typedef Tree<T> MyT;
56  typedef Node<T> NodeT;
57 
58  struct iterator
59  {
60  inline iterator() : curp(NULL) {}
61  inline iterator(NodeT* n) { curp=n; }
62  inline iterator(const iterator& i) : curp(i.curp) {}
63  inline operator const T* () const { assert(curp); return &curp->key; }
64  inline const T* operator->() const { assert(curp); return &curp->key; }
65  inline void operator++() { if(curp) curp=curp->successor(); }
66  inline void operator--() { if(curp) curp=curp->predecessor(); }
67  inline void operator++(int) { if(curp) curp=curp->successor(); }
68  inline void operator--(int) { if(curp) curp=curp->predecessor(); }
69  inline bool operator == (const iterator& i) const { return i.curp==curp; }
70  inline bool operator != (const iterator& i) const { return i.curp!=curp; }
71  inline operator bool() const { return curp!=NULL; }
72  inline bool operator !() const { return curp==NULL; }
73  inline bool end() const { return curp==NULL; }
74 
75  NodeT* curp;
76  };
77 
78  Tree();
79  ~Tree();
80  bool checkValid() const;
81  inline bool empty() const { return root==NULL; }
82  void clear();
83  bool erase(const T&);
84  inline void erase(const iterator& x) { _erase(x.curp); }
85  inline iterator find(const T& key) const { return iterator(_find(key)); }
86  inline iterator insert(const T& key) { return iterator(_insert(key)); }
87  iterator lookup(Lookup type, const T&);
88  void walk(WalkCallback<T>& callback);
89  iterator begin() const;
90  inline iterator end() const { return iterator(); }
91  iterator front() const;
92  iterator back() const;
93 
94  Cmp cmpFunc;
95 
96 private:
97  NodeT* _insert(const T&);
98  NodeT* _find(const T&) const;
99  NodeT* _lookup(Lookup, const T&) const;
100  void _erase(NodeT* x);
101  void _erase_fix(NodeT* x,NodeT* p);
102  void _left_rotate(NodeT* x);
103  void _right_rotate(NodeT* x);
104 
105  NodeT *root;
106 };
107 
108 
109 
110 
111 
112 
113 template <class T>
115 :left(NULL),right(NULL),up(NULL),color(Black)
116 {}
117 
118 template <class T>
119 Node<T>::Node(const T& _key)
120 :left(NULL),right(NULL),up(NULL),key(_key),color(Black)
121 {}
122 
123 template <class T>
125 {
126  if(left) delete left;
127  if(right) delete right;
128 }
129 
130 template <class T>
131 void Node<T>::detatch()
132 {
133  left=right=up=NULL;
134 }
135 
136 template <class T>
138 {
139  MyT *y;
140  const MyT *x;
141 
142  if (right!=NULL)
143  {
144  /* If right is not NULL then go right one and
145  ** then keep going left until we find a node with
146  ** no left pointer.
147  */
148  for (y=right; y->left!=NULL; y=y->left);
149  }
150  else
151  {
152  /* Go up the tree until we get to a node that is on the
153  ** left of its parent (or the root) and then return the
154  ** parent.
155  */
156  y=up;
157  x=this;
158  while(y!=NULL && x==y->right)
159  {
160  x=y;
161  y=y->up;
162  }
163  }
164  return(y);
165 }
166 
167 template <class T>
169 {
170  MyT *y;
171  const MyT *x;
172 
173  if (left!=NULL)
174  {
175  /* If left is not NULL then go left one and
176  ** then keep going right until we find a node with
177  ** no right pointer.
178  */
179  for (y=left; y->right!=NULL; y=y->right);
180  }
181  else
182  {
183  /* Go up the tree until we get to a node that is on the
184  ** right of its parent (or the root) and then return the
185  ** parent.
186  */
187  y=up;
188  x=this;
189  while(y!=NULL && x==y->left)
190  {
191  x=y;
192  y=y->up;
193  }
194  }
195  return(y);
196 }
197 
198 template <class T>
199 void Node<T>::walk(WalkCallback<T>& callback,int level)
200 {
201  if (left==NULL && right==NULL)
202  {
203  callback(key, WalkCallback<T>::Leaf, level);
204  }
205  else
206  {
207  callback(key, WalkCallback<T>::Preorder, level);
208  if(left != NULL) left->walk(callback, level+1);
209  callback(key, WalkCallback<T>::Postorder, level);
210  if(right != NULL) right->walk(callback, level+1);
211  callback(key, WalkCallback<T>::Endorder, level);
212  }
213 }
214 
215 template <class T>
216 bool Node<T>::isValid() const
217 {
218  if (hasColor(Red))
219  {
220  if (!left->hasColor(Black) && !right->hasColor(Black))
221  {
222  //LOG4CXX_ERROR(KrisLibrary::logger(), "Children of red node not both black, x="<< (unsigned long)this);
223  return false;
224  }
225  }
226 
227  if (left)
228  {
229  if (left->up != this)
230  {
231  //LOG4CXX_ERROR(KrisLibrary::logger(), "x->left->up != x, x="<< (unsigned long)this);
232  return false;
233  }
234 
235  if (!left->isValid())
236  return false;
237  }
238 
239  if (right)
240  {
241  if (right->up != this)
242  {
243  //LOG4CXX_ERROR(KrisLibrary::logger(), "x->right->up != x, x="<< (unsigned long)this);
244  return false;
245  }
246 
247  if (!right->isValid())
248  return false;
249  }
250  return true;
251 }
252 
253 template <class T>
255 {
256  if (this==NULL)
257  return(1);
258 
259  int nleft=left->count_black(), nright=right->count_black();
260  if (nleft==-1 || nright==-1)
261  return(-1);
262 
263  if (nleft != nright)
264  {
265  //LOG4CXX_ERROR(KrisLibrary::logger(), "Black count not equal on left & right, x="<< (unsigned long)this);
266  return(-1);
267  }
268 
269  if (hasColor(Black)) nleft++;
270  return(nleft);
271 }
272 
273 template <class T>
274 void Node<T>::dumptree(std::ostream& out,int n)
275 {
276  if (this!=NULL) {
277  n++;
278  out<<"Tree: "<<n<<" "<<(unsigned int)this<<
279  ": color="<<(hasColor(Black)? "Black" : "Red") <<", key="<<key<<
280  ", left="<<(unsigned int)left<<", right="<<(unsigned int)right<<std::endl;
281  left->dumptree(out,n);
282  right->dumptree(out,n);
283  }
284 }
285 
286 /*
287 ** OK here we go, the balanced tree stuff. The algorithm is the
288 ** fairly standard red/black taken from "Introduction to Algorithms"
289 ** by Cormen, Leiserson & Rivest.
290 **
291 ** Basically a red/black balanced tree has the following properties:-
292 ** 1) Every node is either red or black
293 ** 2) A leaf (NULL pointer) is considered black
294 ** 3) If a node is red then its children are black
295 ** 4) Every path from a node to a leaf contains the same no
296 ** of black nodes
297 **
298 ** 3) & 4) above guarantee that the longest path (alternating
299 ** red and black nodes) is only twice as long as the shortest
300 ** path (all black nodes). Thus the tree remains fairly balanced.
301 */
302 
303 template <class T,class Cmp>
305 :root(NULL)
306 {}
307 
308 template <class T,class Cmp>
310 {
311  clear();
312 }
313 
314 template <class T,class Cmp>
315 void Tree<T,Cmp>::clear()
316 {
317  if (root) delete root;
318  root=NULL;
319 }
320 
321 template <class T,class Cmp>
322 bool Tree<T,Cmp>::erase(const T& key)
323 {
324  NodeT *x=_find(key);
325  if (x) {
326  _erase(x);
327  return true;
328  }
329  return false;
330 }
331 
332 template <class T,class Cmp>
333 void Tree<T,Cmp>::walk(WalkCallback<T>& callback)
334 {
335  _walk(root, callback);
336 }
337 
338 template <class T,class Cmp>
340 {
341  NodeT* start=root;
342  //seek the minimum
343  if(start) while(start->left!=NULL) start=start->left;
344  return iterator(start);
345 }
346 
347 template <class T,class Cmp>
348 typename Tree<T,Cmp>::iterator Tree<T,Cmp>::lookup(Lookup mode, const T& key)
349 {
350  if (!root) return iterator(NULL);
351  return iterator(_lookup(mode, key));
352 }
353 
354 template <class T,class Cmp>
356 {
357  NodeT* start=root;
358  //seek the minimum
359  if(start) while(start->left!=NULL) start=start->left;
360  return iterator(start);
361 }
362 
363 template <class T,class Cmp>
365 {
366  NodeT* start=root;
367  //seek the maximum
368  if(start) while(start->right!=NULL) start=start->right;
369  return iterator(start);
370 }
371 
372 /* --------------------------------------------------------------------- */
373 
374 /* Search for and if not found and insert is true, will add a new
375 ** node in. Returns a pointer to the new node, or the node found
376 */
377 template <class T,class Cmp>
378 Node<T>* Tree<T,Cmp>::_insert(const T& key)
379 {
380  NodeT *x,*y,*z;
381  int cmp;
382 
383  y=NULL; /* points to the parent of x */
384  x=root;
385 
386  /* walk x down the tree */
387  while(x!=NULL) {
388  y=x;
389  cmp=cmpFunc(key, x->key);
390 
391  if (cmp<0)
392  x=x->left;
393  else if (cmp>0)
394  x=x->right;
395  else //found the key
396  return x;
397  }
398 
399  z=new NodeT(key);
400  if (z==NULL) {
401  /* Whoops, no memory */
402  return(NULL);
403  }
404 
405  z->up=y;
406  if (y==NULL)
407  {
408  root=z;
409  }
410  else
411  {
412  cmp=cmpFunc(z->key, y->key);
413  if (cmp<0)
414  y->left=z;
415  else
416  y->right=z;
417  }
418 
419  z->left=NULL;
420  z->right=NULL;
421 
422  /* color this new node red */
423  z->setColor(Red);
424 
425  /* Having added a red node, we must now walk back up the tree balancing
426  ** it, by a series of rotations and changing of colors
427  */
428  x=z;
429 
430  /* While we are not at the top and our parent node is red
431  ** N.B. Since the root node is garanteed black, then we
432  ** are also going to stop if we are the child of the root
433  */
434 
435  while(x != root && x->up->hasColor(Red))
436  {
437  /* if our parent is on the left side of our grandparent */
438  if (x->up == x->up->up->left)
439  {
440  /* get the right side of our grandparent (uncle?) */
441  y=x->up->up->right;
442  if (y->hasColor(Red))
443  {
444  /* make our parent black */
445  x->up->setColor(Black);
446  /* make our uncle black */
447  y->setColor(Black);
448  /* make our grandparent red */
449  x->up->up->setColor(Red);
450 
451  /* now consider our grandparent */
452  x=x->up->up;
453  }
454  else
455  {
456  /* if we are on the right side of our parent */
457  if (x == x->up->right)
458  {
459  /* Move up to our parent */
460  x=x->up;
461  _left_rotate(x);
462  }
463 
464  /* make our parent black */
465  x->up->setColor(Black);
466  /* make our grandparent red */
467  x->up->up->setColor(Red);
468  /* right rotate our grandparent */
469  _right_rotate(x->up->up);
470  }
471  }
472  else
473  {
474  /* everything here is the same as above, but
475  ** exchanging left for right
476  */
477 
478  y=x->up->up->left;
479  if (y->hasColor(Red))
480  {
481  x->up->setColor(Black);
482  y->setColor(Black);
483  x->up->up->setColor(Red);
484 
485  x=x->up->up;
486  }
487  else
488  {
489  if (x == x->up->left)
490  {
491  x=x->up;
492  _right_rotate(x);
493  }
494 
495  x->up->setColor(Black);
496  x->up->up->setColor(Red);
497  _left_rotate(x->up->up);
498  }
499  }
500  }
501 
502  /* Set the root node black */
503  root->setColor(Black);
504  return z;
505 }
506 
507 template <class T,class Cmp>
508 Node<T>* Tree<T,Cmp>::_find(const T& key) const
509 {
510  NodeT* x=root;
511  int cmp;
512 
513  /* walk x down the tree */
514  while(x!=NULL) {
515  cmp=cmpFunc(key, x->key);
516 
517  if (cmp<0)
518  x=x->left;
519  else if (cmp>0)
520  x=x->right;
521  else
522  return x;
523  }
524  return NULL;
525 }
526 
527 template <class T,class Cmp>
528 Node<T>* Tree<T,Cmp>::_lookup(Lookup mode, const T& key) const
529 {
530  NodeT *x,*y;
531  int cmp=0;
532  int found=0;
533 
534  y=NULL; /* points to the parent of x */
535  x=root;
536 
537  /* walk x down the tree */
538  while(x!=NULL && found==0)
539  {
540  y=x;
541  cmp=cmpFunc(key, x->key);
542 
543  if (cmp<0)
544  x=x->left;
545  else if (cmp>0)
546  x=x->right;
547  else
548  found=1;
549  }
550 
551  if (found && (mode==Equal || mode==GTEQ || mode==LTEQ))
552  return(x);
553 
554  if (!found && (mode==Equal || mode==Next || mode==Prev))
555  return(NULL);
556 
557  if (mode==GTEQ || (!found && mode==Greater))
558  {
559  if (cmp>0)
560  return(y->successor());
561  else
562  return(y);
563  }
564 
565  if (mode==LTEQ || (!found && mode==Less))
566  {
567  if (cmp<0)
568  return(y->predecessor());
569  else
570  return(y);
571  }
572 
573  if (mode==Next || (found && mode==Greater))
574  return(x->successor());
575 
576  if (mode==Prev || (found && mode==Less))
577  return(x->predecessor());
578 
579  /* Shouldn't get here unless mode=None */
580  return(NULL);
581 }
582 
583 
584 /*
585 ** Rotate our tree thus:-
586 **
587 ** X left_rotate(X)---> Y
588 ** / \ / \
589 ** A Y <--- right_rotate(Y) X C
590 ** / \ / \
591 ** B C A B
592 **
593 ** N.B. This does not change the ordering.
594 **
595 ** We assume that neither X or Y is NULL
596 */
597 
598 template <class T,class Cmp>
600 {
601  NodeT *y;
602 
603  assert(x!=NULL);
604  assert(x->right!=NULL);
605 
606  y=x->right; /* set Y */
607 
608  /* Turn Y's left subtree into X's right subtree (move B)*/
609  x->right = y->left;
610 
611  /* If B is not null, set it's parent to be X */
612  if (y->left != NULL)
613  y->left->up = x;
614 
615  /* Set Y's parent to be what X's parent was */
616  y->up = x->up;
617 
618  /* if X was the root */
619  if (x->up == NULL)
620  {
621  root=y;
622  }
623  else
624  {
625  /* Set X's parent's left or right pointer to be Y */
626  if (x == x->up->left)
627  {
628  x->up->left=y;
629  }
630  else
631  {
632  x->up->right=y;
633  }
634  }
635 
636  /* Put X on Y's left */
637  y->left=x;
638 
639  /* Set X's parent to be Y */
640  x->up = y;
641 }
642 
643 template <class T,class Cmp>
645 {
646  NodeT *x;
647 
648  assert(y!=NULL);
649  assert(y->left!=NULL);
650 
651  x=y->left; /* set X */
652 
653  /* Turn X's right subtree into Y's left subtree (move B) */
654  y->left = x->right;
655 
656  /* If B is not null, set it's parent to be Y */
657  if (x->right != NULL)
658  x->right->up = y;
659 
660  /* Set X's parent to be what Y's parent was */
661  x->up = y->up;
662 
663  /* if Y was the root */
664  if (y->up == NULL)
665  {
666  root=x;
667  }
668  else
669  {
670  /* Set Y's parent's left or right pointer to be X */
671  if (y == y->up->left)
672  {
673  y->up->left=x;
674  }
675  else
676  {
677  y->up->right=x;
678  }
679  }
680 
681  /* Put Y on X's right */
682  x->right=y;
683 
684  /* Set Y's parent to be X */
685  y->up = x;
686 }
687 
688 template <class T,class Cmp>
689 void Tree<T,Cmp>::_erase(NodeT *z)
690 {
691  NodeT *x, *y, *p;
692 
693  if (z->left == NULL || z->right == NULL)
694  y=z;
695  else
696  y=z->successor();
697 
698  p = y->up;
699  if (y->left != NULL)
700  x=y->left;
701  else
702  x=y->right;
703  if(x) x->up=p;
704  if (p == NULL)
705  {
706  root=x;
707  }
708  else
709  {
710  if (y==p->left)
711  p->left = x;
712  else
713  p->right = x;
714  }
715  y->detatch();
716 
717  if (y->hasColor(Black))
718  _erase_fix(x,p);
719 
720 /* DELETED: don't want to be changing iterators around on erase!
721  if(z!=y) {
722  z->key = y->key;
723  }
724  delete y;
725 */
726  if(z!=y) {
727  //sit y into z's place
728  if(z->up) {
729  if(z->up->left == z) z->up->left=y;
730  else { assert(z->up->right == z); z->up->right=y; }
731  }
732  y->up=z->up;
733  if(z->left) z->left->up = y;
734  y->left=z->left;
735  if(z->right) z->right->up = y;
736  y->right=z->right;
737  y->setColor(z->getColor());
738  z->detatch();
739  }
740 
741  delete z;
742 }
743 
744 /* Restore the red-black properties after a delete */
745 template <class T,class Cmp>
747 {
748  NodeT *w;
749  while (x!=root && x->hasColor(Black))
750  {
751  if (x==p->left)
752  {
753  w=p->right;
754  if (w->hasColor(Red))
755  {
756  w->setColor(Black);
757  p->setColor(Red);
758  _left_rotate(p);
759  w=p->right;
760  }
761 
762  if (w->left->hasColor(Black) && w->right->hasColor(Black))
763  {
764  w->setColor(Red);
765  x=p;
766  p=x->up;
767  }
768  else
769  {
770  if (w->right->hasColor(Black))
771  {
772  w->left->setColor(Black);
773  w->setColor(Red);
774  _right_rotate(w);
775  w=p->right;
776  }
777 
778 
779  w->setColor(p->getColor());
780  p->setColor(Black);
781  w->right->setColor(Black);
782  _left_rotate(p);
783  x=root;
784  }
785  }
786  else
787  {
788  w=p->left;
789  if (w->hasColor(Red))
790  {
791  w->setColor(Black);
792  p->setColor(Red);
793  _right_rotate(p);
794  w=p->left;
795  }
796 
797  if (w->right->hasColor(Black) && w->left->hasColor(Black))
798  {
799  w->setColor(Red);
800  x=p;
801  p=x->up;
802  }
803  else
804  {
805  if (w->left->hasColor(Black))
806  {
807  w->right->setColor(Black);
808  w->setColor(Red);
809  _left_rotate(w);
810  w=p->left;
811  }
812 
813  w->setColor(p->getColor());
814  p->setColor(Black);
815  w->left->setColor(Black);
816  _right_rotate(p);
817  x=root;
818  }
819  }
820  }
821 
822  x->setColor(Black);
823 }
824 
825 
826 template <class T,class Cmp>
827 bool Tree<T,Cmp>::checkValid() const
828 {
829  if (root->up!=NULL)
830  {
831  LOG4CXX_ERROR(KrisLibrary::logger(), "Root up pointer not NULL" <<"\n");
832  root->dumptree(std::cerr,0);
833  return false;
834  }
835 
836  if (!root->isValid())
837  {
838  root->dumptree(std::cerr,0);
839  return false;
840  }
841 
842  if (root->count_black()==-1)
843  {
844  LOG4CXX_ERROR(KrisLibrary::logger(),"Error in black count"<<"\n");
845  root->dumptree(std::cerr,0);
846  return false;
847  }
848 
849  return true;
850 }
851 
852 } //namespace RedBlack
853 
854 #endif
Definition: RedBlack.h:58
Definition: RedBlack.h:9
Definition: RedBlack.h:23
Definition: RedBlack.h:16
The logging system used in KrisLibrary.
Definition: RedBlack.h:52