Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

root/trunk/tango/util/container/RedBlack.d

Revision 4012, 27.9 kB (checked in by larsivi, 3 years ago)

Put docs on struct instead of a private typedef

  • Property svn:eol-style set to native
Line 
1 /*******************************************************************************
2
3         copyright:      Copyright (c) 2008 Kris Bell. All rights reserved
4
5         license:        BSD style: $(LICENSE)
6
7         version:        Apr 2008: Initial release
8
9         authors:        Kris, tsalm
10
11         Since:          0.99.7
12
13         Based upon Doug Lea's Java collection package
14
15 *******************************************************************************/
16
17 module tango.util.container.RedBlack;
18
19 private import tango.util.container.model.IContainer;
20
21 private typedef int AttributeDummy;
22
23 /*******************************************************************************
24
25         RedBlack implements basic capabilities of Red-Black trees,
26         an efficient kind of balanced binary tree. The particular
27         algorithms used are adaptations of those in Corman,
28         Lieserson, and Rivest's <EM>Introduction to Algorithms</EM>.
29         This class was inspired by (and code cross-checked with) a
30         similar class by Chuck McManis. The implementations of
31         rebalancings during insertion and deletion are
32         a little trickier than those versions since they
33         don't swap Cell contents or use special dummy nilnodes.
34
35         Doug Lea
36
37 *******************************************************************************/
38
39 struct RedBlack (V, A = AttributeDummy)
40 {
41         alias RedBlack!(V, A) Type;
42         alias Type            *Ref;
43
44         enum : bool {RED = false, BLACK = true}
45
46         /**
47          * Pointer to left child
48         **/
49
50         package Ref     left;
51
52         /**
53          * Pointer to right child
54         **/
55
56         package Ref     right;
57
58         /**
59          * Pointer to parent (null if root)
60         **/
61
62         package Ref     parent;
63
64         package V       value;
65
66         static if (!is(typeof(A) == AttributeDummy))
67         {
68                A        attribute;
69         }
70
71         /**
72          * The node color (RED, BLACK)
73         **/
74
75         package bool    color;
76
77         static if (!is(typeof(A) == AttributeDummy))
78         {
79                 final Ref set (V v, A a)
80                 {
81                         attribute = a;
82                         return set (v);
83                 }
84         }
85
86         /**
87          * Make a new Cell with given value, null links, and BLACK color.
88          * Normally only called to establish a new root.
89         **/
90
91         final Ref set (V v)
92         {
93                 value = v;
94                 left = null;
95                 right = null;
96                 parent = null;
97                 color = BLACK;
98                 return this;
99         }
100
101         /**
102          * Return a new Ref with same value and color as self,
103          * but with null links. (Since it is never OK to have
104          * multiple identical links in a RB tree.)
105         **/
106
107         protected Ref dup (Ref delegate() alloc)
108         {
109                 static if (is(typeof(A) == AttributeDummy))
110                            auto t = alloc().set (value);
111                        else
112                           auto t = alloc().set (value, attribute);
113
114                 t.color = color;
115                 return t;
116         }
117
118
119         /**
120          * See_Also: tango.util.collection.model.View.View.checkImplementation.
121         **/
122         public void checkImplementation ()
123         {
124
125                 // It's too hard to check the property that every simple
126                 // path from node to leaf has same number of black nodes.
127                 // So restrict to the following
128
129                 assert(parent is null ||
130                        this is parent.left ||
131                        this is parent.right);
132
133                 assert(left is null ||
134                        this is left.parent);
135
136                 assert(right is null ||
137                        this is right.parent);
138
139                 assert(color is BLACK ||
140                        (colorOf(left) is BLACK) && (colorOf(right) is BLACK));
141
142                 if (left !is null)
143                         left.checkImplementation();
144                 if (right !is null)
145                         right.checkImplementation();
146         }
147
148         /**
149          * Return the minimum value of the current (sub)tree
150         **/
151
152         Ref leftmost ()
153         {
154                 auto p = this;
155                 for ( ; p.left; p = p.left) {}
156                 return p;
157         }
158
159         /**
160          * Return the maximum value of the current (sub)tree
161         **/
162         Ref rightmost ()
163         {
164                 auto p = this;
165                 for ( ; p.right; p = p.right) {}
166                 return p;
167         }
168
169         /**
170          * Return the root (parentless node) of the tree
171         **/
172         Ref root ()
173         {
174                 auto p = this;
175                 for ( ; p.parent; p = p.parent) {}
176                 return p;
177         }
178
179         /**
180          * Return true if node is a root (i.e., has a null parent)
181         **/
182
183         bool isRoot ()
184         {
185                 return parent is null;
186         }
187
188
189         /**
190          * Return the inorder successor, or null if no such
191         **/
192
193         Ref successor ()
194         {
195                 if (right)
196                     return right.leftmost;
197
198                 auto p = parent;
199                 auto ch = this;
200                 while (p && ch is p.right)
201                       {
202                       ch = p;
203                       p = p.parent;
204                       }
205                 return p;
206         }
207
208         /**
209          * Return the inorder predecessor, or null if no such
210         **/
211
212         Ref predecessor ()
213         {
214                 if (left)
215                     return left.rightmost;
216
217                 auto p = parent;
218                 auto ch = this;
219                 while (p && ch is p.left)
220                       {
221                       ch = p;
222                       p = p.parent;
223                       }
224                 return p;
225         }
226
227         /**
228          * Return the number of nodes in the subtree
229         **/
230         int size ()
231         {
232                 auto c = 1;
233                 if (left)
234                     c += left.size;
235                 if (right)
236                     c += right.size;
237                 return c;
238         }
239
240
241         /**
242          * Return node of current subtree containing value as value(),
243          * if it exists, else null.
244          * Uses Comparator cmp to find and to check equality.
245         **/
246
247         Ref find (V value, Compare!(V) cmp)
248         {
249                 auto t = this;
250                 for (;;)
251                     {
252                     auto diff = cmp (value, t.value);
253                     if (diff is 0)
254                         return t;
255                     else
256                        if (diff < 0)
257                            t = t.left;
258                        else
259                           t = t.right;
260                     if (t is null)
261                         break;
262                     }
263                 return null;
264         }
265
266
267         /**
268          * Return node of subtree matching "value"
269          * or, if none found, the one just after or before 
270          * if it doesn't exist, return null
271          * Uses Comparator cmp to find and to check equality.
272         **/
273         Ref findFirst (V value, Compare!(V) cmp, bool after = true)
274         {
275                 auto t = this;
276                 auto tLower = this;
277                 auto tGreater  = this;
278            
279                 for (;;)
280                     {
281                     auto diff = cmp (value, t.value);
282                     if (diff is 0)
283                         return t;
284                    else
285                       if (diff < 0)
286                          {
287                          tGreater = t;
288                          t = t.left;
289                          }
290                       else
291                          {
292                          tLower = t;
293                          t = t.right;
294                          }
295                    if (t is null)
296                        break;
297                    }
298    
299                 if (after)
300                    {
301                    if (cmp (value, tGreater.value) <= 0)
302                        if (cmp (value, tGreater.value) < 0)
303                            return tGreater;
304                    }
305                 else
306                    {
307                    if (cmp (value, tLower.value) >= 0)
308                        if (cmp (value, tLower.value) > 0)
309                            return tLower;
310                    }
311
312                 return null;
313         }
314        
315         /**
316          * Return number of nodes of current subtree containing value.
317          * Uses Comparator cmp to find and to check equality.
318         **/
319         int count (V value, Compare!(V) cmp)
320         {
321                 auto c = 0;
322                 auto t = this;
323                 while (t)
324                       {
325                       int diff = cmp (value, t.value);
326                       if (diff is 0)
327                          {
328                          ++c;
329                          if (t.left is null)
330                              t = t.right;
331                          else
332                             if (t.right is null)
333                                 t = t.left;
334                             else
335                                {
336                                c += t.right.count (value, cmp);
337                                t = t.left;
338                                }
339                             }
340                          else
341                             if (diff < 0)
342                                 t = t.left;
343                             else
344                                t = t.right;
345                          }
346                 return c;
347         }
348        
349         static if (!is(typeof(A) == AttributeDummy))
350         {
351         Ref findAttribute (A attribute, Compare!(A) cmp)
352         {
353                 auto t = this;
354
355                 while (t)
356                       {
357                       if (t.attribute == attribute)
358                           return t;
359                       else
360                         if (t.right is null)
361                             t = t.left;
362                         else
363                            if (t.left is null)
364                                t = t.right;
365                            else
366                               {
367                               auto p = t.left.findAttribute (attribute, cmp);
368
369                               if (p !is null)
370                                   return p;
371                               else
372                                  t = t.right;
373                               }
374                       }
375                 return null; // not reached
376         }
377
378         int countAttribute (A attrib, Compare!(A) cmp)
379         {
380                 int c = 0;
381                 auto t = this;
382
383                 while (t)
384                       {
385                       if (t.attribute == attribute)
386                           ++c;
387
388                       if (t.right is null)
389                           t = t.left;
390                       else
391                          if (t.left is null)
392                              t = t.right;
393                          else
394                             {
395                             c += t.left.countAttribute (attribute, cmp);
396                             t = t.right;
397                             }
398                       }
399                 return c;
400         }
401
402         /**
403          * find and return a cell holding (key, element), or null if no such
404         **/
405         Ref find (V value, A attribute, Compare!(V) cmp)
406         {
407                 auto t = this;
408
409                 for (;;)
410                     {
411                     int diff = cmp (value, t.value);
412                     if (diff is 0 && t.attribute == attribute)
413                         return t;
414                     else
415                        if (diff <= 0)
416                            t = t.left;
417                        else
418                           t = t.right;
419
420                     if (t is null)
421                         break;
422                     }
423                 return null;
424         }
425
426         }
427
428
429
430         /**
431          * Return a new subtree containing each value of current subtree
432         **/
433
434         Ref copyTree (Ref delegate() alloc)
435         {
436                 auto t = dup (alloc);
437
438                 if (left)
439                    {
440                    t.left = left.copyTree (alloc);
441                    t.left.parent = t;
442                    }
443
444                 if (right)
445                    {
446                    t.right = right.copyTree (alloc);
447                    t.right.parent = t;
448                    }
449
450                 return t;
451         }
452
453
454         /**
455          * There's no generic value insertion. Instead find the
456          * place you want to add a node and then invoke insertLeft
457          * or insertRight.
458          * <P>
459          * Insert Cell as the left child of current node, and then
460          * rebalance the tree it is in.
461          * @param Cell the Cell to add
462          * @param root, the root of the current tree
463          * Returns: the new root of the current tree. (Rebalancing
464          * can change the root!)
465         **/
466
467
468         Ref insertLeft (Ref cell, Ref root)
469         {
470                 left = cell;
471                 cell.parent = this;
472                 return cell.fixAfterInsertion (root);
473         }
474
475         /**
476          * Insert Cell as the right child of current node, and then
477          * rebalance the tree it is in.
478          * @param Cell the Cell to add
479          * @param root, the root of the current tree
480          * Returns: the new root of the current tree. (Rebalancing
481          * can change the root!)
482         **/
483
484         Ref insertRight (Ref cell, Ref root)
485         {
486                 right = cell;
487                 cell.parent = this;
488                 return cell.fixAfterInsertion (root);
489         }
490
491
492         /**
493          * Delete the current node, and then rebalance the tree it is in
494          * @param root the root of the current tree
495          * Returns: the new root of the current tree. (Rebalancing
496          * can change the root!)
497         **/
498
499
500         Ref remove (Ref root)
501         {
502                 // handle case where we are only node
503                 if (left is null && right is null && parent is null)
504                     return null;
505
506                 // if strictly internal, swap places with a successor
507                 if (left && right)
508                    {
509                    auto s = successor;
510
511                    // To work nicely with arbitrary subclasses of Ref, we don't want to
512                    // just copy successor's fields. since we don't know what
513                    // they are.  Instead we swap positions _in the tree.
514                    root = swapPosition (this, s, root);
515                    }
516
517                 // Start fixup at replacement node (normally a child).
518                 // But if no children, fake it by using self
519
520                 if (left is null && right is null)
521                    {
522                    if (color is BLACK)
523                        root = this.fixAfterDeletion (root);
524
525                    // Unlink  (Couldn't before since fixAfterDeletion needs parent ptr)
526                    if (parent)
527                       {
528                       if (this is parent.left)
529                           parent.left = null;
530                       else
531                          if (this is parent.right)
532                              parent.right = null;
533                       parent = null;
534                       }
535                    }
536                 else
537                    {
538                    auto replacement = left;
539                    if (replacement is null)
540                        replacement = right;
541
542                    // link replacement to parent
543                    replacement.parent = parent;
544
545                    if (parent is null)
546                        root = replacement;
547                    else
548                       if (this is parent.left)
549                           parent.left = replacement;
550                       else
551                          parent.right = replacement;
552
553                    left = null;
554                    right = null;
555                    parent = null;
556        
557                    // fix replacement
558                    if (color is BLACK)
559                        root = replacement.fixAfterDeletion (root);
560                    }
561                 return root;
562         }
563
564         /**
565          * Swap the linkages of two nodes in a tree.
566          * Return new root, in case it changed.
567         **/
568
569         static Ref swapPosition (Ref x, Ref y, Ref root)
570         {
571                 /* Too messy. TODO: find sequence of assigments that are always OK */
572
573                 auto px = x.parent;
574                 bool xpl = px !is null && x is px.left;
575                 auto lx = x.left;
576                 auto rx = x.right;
577
578                 auto py = y.parent;
579                 bool ypl = py !is null && y is py.left;
580                 auto ly = y.left;
581                 auto ry = y.right;
582
583                 if (x is py)
584                    {
585                    y.parent = px;
586                    if (px !is null)
587                        if (xpl)
588                            px.left = y;
589                        else
590                           px.right = y;
591
592                    x.parent = y;
593                    if (ypl)
594                       {
595                       y.left = x;
596                       y.right = rx;
597                       if (rx !is null)
598                       rx.parent = y;
599                       }
600                    else
601                       {
602                       y.right = x;
603                       y.left = lx;
604                       if (lx !is null)
605                       lx.parent = y;
606                       }
607
608                    x.left = ly;
609                    if (ly !is null)
610                        ly.parent = x;
611
612                    x.right = ry;
613                    if (ry !is null)
614                        ry.parent = x;
615                    }
616                 else
617                    if (y is px)
618                       {
619                       x.parent = py;
620                       if (py !is null)
621                           if (ypl)
622                               py.left = x;
623                           else
624                              py.right = x;
625
626                       y.parent = x;
627                       if (xpl)
628                          {
629                          x.left = y;
630                          x.right = ry;
631                          if (ry !is null)
632                              ry.parent = x;
633                          }
634                       else
635                          {
636                          x.right = y;
637                          x.left = ly;
638                          if (ly !is null)
639                              ly.parent = x;
640                          }
641
642                       y.left = lx;
643                       if (lx !is null)
644                           lx.parent = y;
645
646                       y.right = rx;
647                       if (rx !is null)
648                           rx.parent = y;
649                       }
650                    else
651                       {
652                       x.parent = py;
653                       if (py !is null)
654                           if (ypl)
655                               py.left = x;
656                           else
657                              py.right = x;
658
659                       x.left = ly;
660                       if (ly !is null)
661                           ly.parent = x;
662
663                       x.right = ry;
664                       if (ry !is null)
665                           ry.parent = x;
666        
667                       y.parent = px;
668                       if (px !is null)
669                           if (xpl)
670                               px.left = y;
671                           else
672                              px.right = y;
673
674                       y.left = lx;
675                       if (lx !is null)
676                           lx.parent = y;
677
678                       y.right = rx;
679                       if (rx !is null)
680                           rx.parent = y;
681                       }
682
683                 bool c = x.color;
684                 x.color = y.color;
685                 y.color = c;
686
687                 if (root is x)
688                     root = y;
689                 else
690                    if (root is y)
691                        root = x;
692                 return root;
693         }
694
695
696
697         /**
698          * Return color of node p, or BLACK if p is null
699          * (In the CLR version, they use
700          * a special dummy `nil' node for such purposes, but that doesn't
701          * work well here, since it could lead to creating one such special
702          * node per real node.)
703          *
704         **/
705
706         static bool colorOf (Ref p)
707         {
708                 return (p is null) ? BLACK : p.color;
709         }
710
711         /**
712          * return parent of node p, or null if p is null
713         **/
714         static Ref parentOf (Ref p)
715         {
716                 return (p is null) ? null : p.parent;
717         }
718
719         /**
720          * Set the color of node p, or do nothing if p is null
721         **/
722
723         static void setColor (Ref p, bool c)
724         {
725                 if (p !is null)
726                     p.color = c;
727         }
728
729         /**
730          * return left child of node p, or null if p is null
731         **/
732
733         static Ref leftOf (Ref p)
734         {
735                 return (p is null) ? null : p.left;
736         }
737
738         /**
739          * return right child of node p, or null if p is null
740         **/
741
742         static Ref rightOf (Ref p)
743         {
744                 return (p is null) ? null : p.right;
745         }
746
747
748         /** From CLR **/
749         package Ref rotateLeft (Ref root)
750         {
751                 auto r = right;
752                 right = r.left;
753
754                 if (r.left)
755                     r.left.parent = this;
756
757                 r.parent = parent;
758                 if (parent is null)
759                     root = r;
760                 else
761                    if (parent.left is this)
762                        parent.left = r;
763                    else
764                       parent.right = r;
765
766                 r.left = this;
767                 parent = r;
768                 return root;
769         }
770
771         /** From CLR **/
772         package Ref rotateRight (Ref root)
773         {
774                 auto l = left;
775                 left = l.right;
776
777                 if (l.right !is null)
778                    l.right.parent = this;
779
780                 l.parent = parent;
781                 if (parent is null)
782                     root = l;
783                 else
784                    if (parent.right is this)
785                        parent.right = l;
786                    else
787                       parent.left = l;
788
789                 l.right = this;
790                 parent = l;
791                 return root;
792         }
793
794
795         /** From CLR **/
796         package Ref fixAfterInsertion (Ref root)
797         {
798                 color = RED;
799                 auto x = this;
800
801                 while (x && x !is root && x.parent.color is RED)
802                       {
803                       if (parentOf(x) is leftOf(parentOf(parentOf(x))))
804                          {
805                          auto y = rightOf(parentOf(parentOf(x)));
806                          if (colorOf(y) is RED)
807                             {
808                             setColor(parentOf(x), BLACK);
809                             setColor(y, BLACK);
810                             setColor(parentOf(parentOf(x)), RED);
811                             x = parentOf(parentOf(x));
812                             }
813                          else
814                             {
815                             if (x is rightOf(parentOf(x)))
816                                {
817                                x = parentOf(x);
818                                root = x.rotateLeft(root);
819                                }
820
821                             setColor(parentOf(x), BLACK);
822                             setColor(parentOf(parentOf(x)), RED);
823                             if (parentOf(parentOf(x)) !is null)
824                                 root = parentOf(parentOf(x)).rotateRight(root);
825                             }
826                          }
827                       else
828                          {
829                          auto y = leftOf(parentOf(parentOf(x)));
830                          if (colorOf(y) is RED)
831                             {
832                             setColor(parentOf(x), BLACK);
833                             setColor(y, BLACK);
834                             setColor(parentOf(parentOf(x)), RED);
835                             x = parentOf(parentOf(x));
836                             }
837                          else
838                             {
839                             if (x is leftOf(parentOf(x)))
840                                {
841                                x = parentOf(x);
842                                root = x.rotateRight(root);
843                                }
844        
845                             setColor(parentOf(x), BLACK);
846                             setColor(parentOf(parentOf(x)), RED);
847                             if (parentOf(parentOf(x)) !is null)
848                                 root = parentOf(parentOf(x)).rotateLeft(root);
849                             }
850                          }
851                       }
852                 root.color = BLACK;
853                 return root;
854         }
855
856
857
858         /** From CLR **/
859         package Ref fixAfterDeletion(Ref root)
860         {
861                 auto x = this;
862                 while (x !is root && colorOf(x) is BLACK)
863                       {
864                       if (x is leftOf(parentOf(x)))
865                          {
866                          auto sib = rightOf(parentOf(x));
867                          if (colorOf(sib) is RED)
868                             {
869                             setColor(sib, BLACK);
870                             setColor(parentOf(x), RED);
871                             root = parentOf(x).rotateLeft(root);
872                             sib = rightOf(parentOf(x));
873                             }
874                          if (colorOf(leftOf(sib)) is BLACK && colorOf(rightOf(sib)) is BLACK)
875                             {
876                             setColor(sib, RED);
877                             x = parentOf(x);
878                             }
879                          else
880                             {
881                             if (colorOf(rightOf(sib)) is BLACK)
882                                {
883                                setColor(leftOf(sib), BLACK);
884                                setColor(sib, RED);
885                                root = sib.rotateRight(root);
886                                sib = rightOf(parentOf(x));
887                                }
888
889                             setColor(sib, colorOf(parentOf(x)));
890                             setColor(parentOf(x), BLACK);
891                             setColor(rightOf(sib), BLACK);
892                             root = parentOf(x).rotateLeft(root);
893                             x = root;
894                             }
895                          }
896                       else
897                          {
898                          auto sib = leftOf(parentOf(x));
899                          if (colorOf(sib) is RED)
900                             {
901                             setColor(sib, BLACK);
902                             setColor(parentOf(x), RED);
903                             root = parentOf(x).rotateRight(root);
904                             sib = leftOf(parentOf(x));
905                             }
906
907                          if (colorOf(rightOf(sib)) is BLACK && colorOf(leftOf(sib)) is BLACK)
908                             {
909                             setColor(sib, RED);
910                             x = parentOf(x);
911                             }
912                          else
913                             {
914                             if (colorOf(leftOf(sib)) is BLACK)
915                                {
916                                setColor(rightOf(sib), BLACK);
917                                setColor(sib, RED);
918                                root = sib.rotateLeft(root);
919                                sib = leftOf(parentOf(x));
920                                }
921
922                             setColor(sib, colorOf(parentOf(x)));
923                             setColor(parentOf(x), BLACK);
924                             setColor(leftOf(sib), BLACK);
925                             root = parentOf(x).rotateRight(root);
926                             x = root;
927                             }
928                          }
929                       }
930
931                 setColor(x, BLACK);
932                 return root;
933         }
934 }
Note: See TracBrowser for help on using the browser.