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, 1 month 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