Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TBtree.cxx
Go to the documentation of this file.
1// @(#)root/cont:$Id$
2// Author: Fons Rademakers 10/10/95
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/** \class TBtree
13\ingroup Containers
14B-tree class. TBtree inherits from the TSeqCollection ABC.
15
16## B-tree Implementation notes
17
18This implements B-trees with several refinements. Most of them can be found
19in Knuth Vol 3, but some were developed to adapt to restrictions imposed
20by C++. First, a restatement of Knuth's properties that a B-tree must
21satisfy, assuming we make the enhancement he suggests in the paragraph
22at the bottom of page 476. Instead of storing null pointers to non-existent
23nodes (which Knuth calls the leaves) we utilize the space to store keys.
24Therefore, what Knuth calls level (l-1) is the bottom of our tree, and
25we call the nodes at this level LeafNodes. Other nodes are called InnerNodes.
26The other enhancement we have adopted is in the paragraph at the bottom of
27page 477: overflow control.
28
29The following are modifications of Knuth's properties on page 478:
30
31 1. Every InnerNode has at most Order keys, and at most Order+1 sub-trees.
32 2. Every LeafNode has at most 2*(Order+1) keys.
33 3. An InnerNode with k keys has k+1 sub-trees.
34 4. Every InnerNode that is not the root has at least InnerLowWaterMark keys.
35 5. Every LeafNode that is not the root has at least LeafLowWaterMark keys.
36 6. If the root is a LeafNode, it has at least one key.
37 7. If the root is an InnerNode, it has at least one key and two sub-trees.
38 8. All LeafNodes are the same distance from the root as all the other
39 LeafNodes.
40 9. For InnerNode n with key n[i].key, then sub-tree n[i-1].tree contains
41 all keys < n[i].key, and sub-tree n[i].tree contains all keys
42 >= n[i].key.
43 10. Order is at least 3.
44
45The values of InnerLowWaterMark and LeafLowWaterMark may actually be set
46by the user when the tree is initialized, but currently they are set
47automatically to:
48~~~ {.cpp}
49 InnerLowWaterMark = ceiling(Order/2)
50 LeafLowWaterMark = Order - 1
51~~~
52If the tree is only filled, then all the nodes will be at least 2/3 full.
53They will almost all be exactly 2/3 full if the elements are added to the
54tree in order (either increasing or decreasing). [Knuth says McCreight's
55experiments showed almost 100% memory utilization. I don't see how that
56can be given the algorithms that Knuth gives. McCreight must have used
57a different scheme for balancing. [No, he used a different scheme for
58splitting: he did a two-way split instead of the three way split as we do
59here. Which means that McCreight does better on insertion of ordered data,
60but we should do better on insertion of random data.]]
61
62It must also be noted that B-trees were designed for DISK access algorithms,
63not necessarily in-memory sorting, as we intend it to be used here. However,
64if the order is kept small (< 6?) any inefficiency is negligible for
65in-memory sorting. Knuth points out that balanced trees are actually
66preferable for memory sorting. I'm not sure that I believe this, but
67it's interesting. Also, deleting elements from balanced binary trees, being
68beyond the scope of Knuth's book (p. 465), is beyond my scope. B-trees
69are good enough.
70
71A B-tree is declared to be of a certain ORDER (3 by default). This number
72determines the number of keys contained in any interior node of the tree.
73Each interior node will contain ORDER keys, and therefore ORDER+1 pointers
74to sub-trees. The keys are numbered and indexed 1 to ORDER while the
75pointers are numbered and indexed 0 to ORDER. The 0th ptr points to the
76sub-tree of all elements that are less than key[1]. Ptr[1] points to the
77sub-tree that contains all the elements greater than key[1] and less than
78key[2]. etc. The array of pointers and keys is allocated as ORDER+1
79pairs of keys and nodes, meaning that one key field (key[0]) is not used
80and therefore wasted. Given that the number of interior nodes is
81small, that this waste allows fewer cases of special code, and that it
82is useful in certain of the methods, it was felt to be a worthwhile waste.
83
84The size of the exterior nodes (leaf nodes) does not need to be related to
85the size of the interior nodes at all. Since leaf nodes contain only
86keys, they may be as large or small as we like independent of the size
87of the interior nodes. For no particular reason other than it seems like
88a good idea, we will allocate 2*(ORDER+1) keys in each leaf node, and they
89will be numbered and indexed from 0 to 2*ORDER+1. It does have the advantage
90of keeping the size of the leaf and interior arrays the same, so that if we
91find allocation and de-allocation of these arrays expensive, we can modify
92their allocation to use a garbage ring, or something.
93
94Both of these numbers will be run-time constants associated with each tree
95(each tree at run-time can be of a different order). The variable "order"
96is the order of the tree, and the inclusive upper limit on the indices of
97the keys in the interior nodes. The variable "order2" is the inclusive
98upper limit on the indices of the leaf nodes, and is designed
99~~~ {.cpp}
100 (1) to keep the sizes of the two kinds of nodes the same;
101 (2) to keep the expressions involving the arrays of keys looking
102 somewhat the same: lower limit upper limit
103 for inner nodes: 1 order
104 for leaf nodes: 0 order2
105 Remember that index 0 of the inner nodes is special.
106~~~
107Currently, order2 = 2*(order+1).
108~~~ {.cpp}
109 Picture: (also see Knuth Vol 3 pg 478)
110
111 +--+--+--+--+--+--...
112 | | | | | |
113 parent--->| | | |
114 | | | |
115 +*-+*-+*-+--+--+--...
116 | | |
117 +----+ | +-----+
118 | +-----+ |
119 V | V
120 +----------+ | +----------+
121 | | | | |
122 this->| | | | |<--sib
123 +----------+ | +----------+
124 V
125 data
126~~~
127It is conceptually VERY convenient to think of the data as being the
128very first element of the sib node. Any primitive that tells sib to
129perform some action on n nodes should include this 'hidden' element.
130For InnerNodes, the hidden element has (physical) index 0 in the array,
131and in LeafNodes, the hidden element has (virtual) index -1 in the array.
132Therefore, there are two 'size' primitives for nodes:
133~~~ {.cpp}
134Psize - the physical size: how many elements are contained in the
135 array in the node.
136Vsize - the 'virtual' size; if the node is pointed to by
137 element 0 of the parent node, then Vsize == Psize;
138 otherwise the element in the parent item that points to this
139 node 'belongs' to this node, and Vsize == Psize+1;
140~~~
141Parent nodes are always InnerNodes.
142
143These are the primitive operations on Nodes:
144~~~ {.cpp}
145Append(elt) - adds an element to the end of the array of elements in a
146 node. It must never be called where appending the element
147 would fill the node.
148Split() - divide a node in two, and create two new nodes.
149SplitWith(sib) - create a third node between this node and the sib node,
150 divvying up the elements of their arrays.
151PushLeft(n) - move n elements into the left sibling
152PushRight(n) - move n elements into the right sibling
153BalanceWithRight() - even up the number of elements in the two nodes.
154BalanceWithLeft() - ditto
155~~~
156To allow this implementation of btrees to also be an implementation of
157sorted arrays/lists, the overhead is included to allow O(log n) access
158of elements by their rank (`give me the 5th largest element').
159Therefore, each Item keeps track of the number of keys in and below it
160in the tree (remember, each item's tree is all keys to the RIGHT of the
161item's own key).
162~~~ {.cpp}
163[ [ < 0 1 2 3 > 4 < 5 6 7 > 8 < 9 10 11 12 > ] 13 [ < 14 15 16 > 17 < 18 19 20 > ] ]
164 4 1 1 1 1 4 1 1 1 5 1 1 1 1 7 3 1 1 1 4 1 1 1
165~~~
166*/
167
168#include "TBtree.h"
169#include "TBuffer.h"
170#include "TObject.h"
171
172#include <cstdlib>
173
174
175
176////////////////////////////////////////////////////////////////////////////////
177/// Create a B-tree of certain order (by default 3).
178
180{
181 Init(order);
182}
183
184////////////////////////////////////////////////////////////////////////////////
185/// Delete B-tree. Objects are not deleted unless the TBtree is the
186/// owner (set via SetOwner()).
187
189{
190 if (fRoot) {
191 Clear();
193 }
194}
195
196////////////////////////////////////////////////////////////////////////////////
197/// Add object to B-tree.
198
200{
201 if (IsArgNull("Add", obj)) return;
202 if (!obj->IsSortable()) {
203 Error("Add", "object must be sortable");
204 return;
205 }
206 if (!fRoot) {
207 fRoot = new TBtLeafNode(nullptr, obj, this);
208 R__CHECK(fRoot != nullptr);
209 IncrNofKeys();
210 } else {
211 TBtNode *loc;
212 Int_t idx;
213 if (fRoot->Found(obj, &loc, &idx)) {
214 // loc and idx are set to either where the object
215 // was found, or where it should go in the Btree.
216 // Nothing is here now, but later we might give the user
217 // the ability to declare a B-tree as `unique elements only',
218 // in which case we would handle an exception here.
219 }
220 loc->Add(obj, idx);
221 }
222}
223
224////////////////////////////////////////////////////////////////////////////////
225/// Cannot use this method since B-tree decides order.
226
228{
229 MayNotUse("After");
230 return nullptr;
231}
232
233////////////////////////////////////////////////////////////////////////////////
234/// May not use this method since B-tree decides order.
235
237{
238 MayNotUse("Before");
239 return nullptr;
240}
241
242////////////////////////////////////////////////////////////////////////////////
243/// Remove all objects from B-tree. Does NOT delete objects unless the TBtree
244/// is the owner (set via SetOwner()).
245
247{
248 if (IsOwner())
249 Delete();
250 else {
252 fSize = 0;
253 }
254}
255
256////////////////////////////////////////////////////////////////////////////////
257/// Remove all objects from B-tree AND delete all heap based objects.
258
260{
261 for (Int_t i = 0; i < fSize; i++) {
262 TObject *obj = At(i);
263 if (obj && obj->IsOnHeap())
265 }
267 fSize = 0;
268}
269
270////////////////////////////////////////////////////////////////////////////////
271/// Find object using its name (see object's GetName()). Requires sequential
272/// search of complete tree till object is found.
273
274TObject *TBtree::FindObject(const char *name) const
275{
277}
278
279////////////////////////////////////////////////////////////////////////////////
280/// Find object using the objects Compare() member function.
281
283{
284 if (!obj->IsSortable()) {
285 Error("FindObject", "object must be sortable");
286 return nullptr;
287 }
288 if (!fRoot)
289 return nullptr;
290 else {
291 TBtNode *loc;
292 Int_t idx;
293 return fRoot->Found(obj, &loc, &idx);
294 }
295}
296
297////////////////////////////////////////////////////////////////////////////////
298/// Add object and return its index in the tree.
299
301{
302 Int_t r;
303 if (!obj.IsSortable()) {
304 Error("IdxAdd", "object must be sortable");
305 return -1;
306 }
307 if (!fRoot) {
308 fRoot = new TBtLeafNode(nullptr, &obj, this);
309 R__ASSERT(fRoot != nullptr);
310 IncrNofKeys();
311 r = 0;
312 } else {
313 TBtNode *loc;
314 int idx;
315 if (fRoot->Found(&obj, &loc, &idx)) {
316 // loc and idx are set to either where the object
317 // was found, or where it should go in the Btree.
318 // Nothing is here now, but later we might give the user
319 // the ability to declare a B-tree as `unique elements only',
320 // in which case we would handle an exception here.
321 // std::cerr << "Multiple entry warning\n";
322 } else {
323 R__CHECK(loc->fIsLeaf);
324 }
325 if (loc->fIsLeaf) {
326 if (!loc->fParent)
327 r = idx;
328 else
329 r = idx + loc->fParent->FindRankUp(loc);
330 } else {
332 r = iloc->FindRankUp(iloc->GetTree(idx));
333 }
334 loc->Add(&obj, idx);
335 }
336 R__CHECK(r == Rank(&obj) || &obj == (*this)[r]);
337 return r;
338}
339
340////////////////////////////////////////////////////////////////////////////////
341/// Initialize a B-tree.
342
344{
345 if (order < 3) {
346 Warning("Init", "order must be at least 3");
347 order = 3;
348 }
349 fRoot = nullptr;
350 fOrder = order;
351 fOrder2 = 2 * (fOrder+1);
352 fLeafMaxIndex = fOrder2 - 1; // fItem[0..fOrder2-1]
353 fInnerMaxIndex = fOrder; // fItem[1..fOrder]
354 //
355 // the low water marks trigger an exploration for balancing
356 // or merging nodes.
357 // When the size of a node falls below X, then it must be possible to
358 // either balance this node with another node, or it must be possible
359 // to merge this node with another node.
360 // This can be guaranteed only if (this->Size() < (MaxSize()-1)/2).
361 //
362 //
363
364 // == MaxSize() satisfies the above because we compare
365 // lowwatermark with fLast
366 fLeafLowWaterMark = ((fLeafMaxIndex+1)-1) / 2 - 1;
367 fInnerLowWaterMark = (fOrder-1) / 2;
368}
369
370//______________________________________________________________________________
371//void TBtree::PrintOn(std::ostream& out) const
372//{
373// // Print a B-tree.
374//
375// if (!fRoot)
376// out << "<empty>";
377// else
378// fRoot->PrintOn(out);
379//}
380
381////////////////////////////////////////////////////////////////////////////////
382/// Returns a B-tree iterator.
383
385{
386 return new TBtreeIter(this, dir);
387}
388
389////////////////////////////////////////////////////////////////////////////////
390/// Returns the rank of the object in the tree.
391
392Int_t TBtree::Rank(const TObject *obj) const
393{
394 if (!obj->IsSortable()) {
395 Error("Rank", "object must be sortable");
396 return -1;
397 }
398 if (!fRoot)
399 return -1;
400 else
401 return fRoot->FindRank(obj);
402}
403
404////////////////////////////////////////////////////////////////////////////////
405/// Remove an object from the tree.
406
408{
409 if (!obj->IsSortable()) {
410 Error("Remove", "object must be sortable");
411 return nullptr;
412 }
413 if (!fRoot)
414 return nullptr;
415
416 TBtNode *loc;
417 Int_t idx;
418 TObject *ob = fRoot->Found(obj, &loc, &idx);
419 if (!ob)
420 return nullptr;
421 loc->Remove(idx);
422 return ob;
423}
424
425////////////////////////////////////////////////////////////////////////////////
426/// The root of the tree is full. Create an InnerNode that
427/// points to it, and then inform the InnerNode that it is full.
428
430{
432 fRoot = new TBtInnerNode(nullptr, this, oldroot);
433 R__ASSERT(fRoot != nullptr);
434 oldroot->Split();
435}
436
437////////////////////////////////////////////////////////////////////////////////
438/// If root is empty clean up its space.
439
441{
442 if (fRoot->fIsLeaf) {
444 R__CHECK(lroot->Psize() == 0);
445 delete lroot;
446 fRoot = nullptr;
447 } else {
449 R__CHECK(iroot->Psize() == 0);
450 fRoot = iroot->GetTree(0);
451 fRoot->fParent = nullptr;
452 delete iroot;
453 }
454}
455
456////////////////////////////////////////////////////////////////////////////////
457/// Stream all objects in the btree to or from the I/O buffer.
458
460{
462 if (b.IsReading()) {
463 b.ReadVersion(&R__s, &R__c); //Version_t v = b.ReadVersion();
464 b >> fOrder;
465 b >> fOrder2;
468 b >> fInnerMaxIndex;
469 b >> fLeafMaxIndex;
471 b.CheckByteCount(R__s, R__c,TBtree::IsA());
472 } else {
473 R__c = b.WriteVersion(TBtree::IsA(), kTRUE);
474 b << fOrder;
475 b << fOrder2;
478 b << fInnerMaxIndex;
479 b << fLeafMaxIndex;
481 b.SetByteCount(R__c, kTRUE);
482 }
483}
484
485
486/** \class TBtItem
487Item stored in inner nodes of a TBtree.
488*/
489
490////////////////////////////////////////////////////////////////////////////////
491/// Create an item to be stored in the tree. An item contains a counter
492/// of the number of keys (i.e. objects) in the node. A pointer to the
493/// node and a pointer to the object being stored.
494
496{
497 fNofKeysInTree = 0;
498 fTree = nullptr;
499 fKey = nullptr;
500}
501
502////////////////////////////////////////////////////////////////////////////////
503/// Create an item to be stored in the tree. An item contains a counter
504/// of the number of keys (i.e. objects) in the node. A pointer to the
505/// node and a pointer to the object being stored.
506
508{
509 fNofKeysInTree = n->NofKeys()+1;
510 fTree = n;
511 fKey = obj;
512}
513
514////////////////////////////////////////////////////////////////////////////////
515/// Create an item to be stored in the tree. An item contains a counter
516/// of the number of keys (i.e. objects) in the node. A pointer to the
517/// node and a pointer to the object being stored.
518
520{
521 fNofKeysInTree = n->NofKeys()+1;
522 fTree = n;
523 fKey = obj;
524}
525
526////////////////////////////////////////////////////////////////////////////////
527/// Delete a tree item.
528
532
533/** \class TBtNode
534Abstract base class (ABC) of a TBtree node.
535*/
536
537////////////////////////////////////////////////////////////////////////////////
538/// Create a B-tree node.
539
541{
542 fLast = -1;
543 fIsLeaf = isleaf;
544 fParent = p;
545 if (!p) {
546 R__CHECK(t != nullptr);
547 fTree = t;
548 } else
549#ifdef cxxbug
550// BUG in the cxx compiler. cxx complains that it cannot access fTree
551// from TBtInnerNode. To reproduce the cxx bug uncomment the following line
552// and delete the line after.
553// fTree = p->fTree;
554 fTree = p->GetParentTree();
555#else
556 fTree = p->fTree;
557#endif
558}
559
560////////////////////////////////////////////////////////////////////////////////
561/// Delete a B-tree node.
562
566
567/** \class TBtreeIter
568// Iterator of btree.
569*/
570
571
572////////////////////////////////////////////////////////////////////////////////
573/// Create a B-tree iterator.
574
576 : fTree(t), fCurCursor(0), fCursor(0), fDirection(dir)
577{
578 Reset();
579}
580
581////////////////////////////////////////////////////////////////////////////////
582/// Copy ctor.
583
585{
586 fTree = iter.fTree;
587 fCursor = iter.fCursor;
588 fCurCursor = iter.fCurCursor;
589 fDirection = iter.fDirection;
590}
591
592////////////////////////////////////////////////////////////////////////////////
593/// Overridden assignment operator.
594
596{
597 if (this != &rhs && rhs.IsA() == TBtreeIter::Class()) {
598 const TBtreeIter &rhs1 = (const TBtreeIter &)rhs;
599 fTree = rhs1.fTree;
600 fCursor = rhs1.fCursor;
601 fCurCursor = rhs1.fCurCursor;
602 fDirection = rhs1.fDirection;
603 }
604 return *this;
605}
606
607////////////////////////////////////////////////////////////////////////////////
608/// Overloaded assignment operator.
609
611{
612 if (this != &rhs) {
613 fTree = rhs.fTree;
614 fCursor = rhs.fCursor;
615 fCurCursor = rhs.fCurCursor;
616 fDirection = rhs.fDirection;
617 }
618 return *this;
619}
620
621////////////////////////////////////////////////////////////////////////////////
622/// Reset the B-tree iterator.
623
625{
627 fCursor = 0;
628 else
629 fCursor = fTree->GetSize() - 1;
630
632}
633
634////////////////////////////////////////////////////////////////////////////////
635/// Get next object from B-tree. Returns 0 when no more objects in tree.
636
638{
640 if (fDirection == kIterForward) {
641 if (fCursor < fTree->GetSize())
642 return (*fTree)[fCursor++];
643 } else {
644 if (fCursor >= 0)
645 return (*fTree)[fCursor--];
646 }
647 return nullptr;
648}
649
650////////////////////////////////////////////////////////////////////////////////
651/// This operator compares two TIterator objects.
652
654{
655 if (aIter.IsA() == TBtreeIter::Class()) {
656 const TBtreeIter &iter(dynamic_cast<const TBtreeIter &>(aIter));
657 return (fCurCursor != iter.fCurCursor);
658 }
659 return false; // for base class we don't implement a comparison
660}
661
662////////////////////////////////////////////////////////////////////////////////
663/// This operator compares two TBtreeIter objects.
664
666{
667 return (fCurCursor != aIter.fCurCursor);
668}
669
670////////////////////////////////////////////////////////////////////////////////
671/// Return current object or nullptr.
672
674{
675 return (((fCurCursor >= 0) && (fCurCursor < fTree->GetSize())) ?
676 (*fTree)[fCurCursor] : nullptr);
677}
678
679/** \class TBtInnerNode
680// Inner node of a TBtree.
681*/
682
683////////////////////////////////////////////////////////////////////////////////
684/// Create a B-tree innernode.
685
687{
688 const Int_t index = MaxIndex() + 1;
689 fItem = new TBtItem[ index ];
690 if (!fItem)
691 ::Fatal("TBtInnerNode::TBtInnerNode", "no more memory");
692}
693
694////////////////////////////////////////////////////////////////////////////////
695/// Called only by TBtree to initialize the TBtInnerNode that is
696/// about to become the root.
697
699 : TBtNode(0, parent, tree)
700{
701 fItem = new TBtItem[MaxIndex()+1];
702 if (!fItem)
703 ::Fatal("TBtInnerNode::TBtInnerNode", "no more memory");
704 Append(nullptr, oldroot);
705}
706
707////////////////////////////////////////////////////////////////////////////////
708/// Constructor.
709
711{
712 if (fLast > 0)
713 delete fItem[0].fTree;
714 for (Int_t i = 1; i <= fLast; i++)
715 delete fItem[i].fTree;
716
717 delete [] fItem;
718}
719
720////////////////////////////////////////////////////////////////////////////////
721/// This is called only from TBtree::Add().
722
724{
725 R__ASSERT(index >= 1 && obj->IsSortable());
727 ln->Add(obj, ln->fLast+1);
728}
729
730////////////////////////////////////////////////////////////////////////////////
731/// Add one element.
732
734{
735 R__ASSERT(0 <= at && at <= fLast+1);
737 for (Int_t i = fLast+1; i > at ; i--)
738 GetItem(i) = GetItem(i-1);
739 SetItem(at, itm);
740 fLast++;
741}
742
743////////////////////////////////////////////////////////////////////////////////
744/// Add one element.
745
747{
748 TBtItem newitem(k, t);
749 AddElt(newitem, at);
750}
751
752////////////////////////////////////////////////////////////////////////////////
753/// Add one element.
754
756{
757 AddElt(itm, at);
758 if (IsFull())
759 InformParent();
760}
761
762////////////////////////////////////////////////////////////////////////////////
763/// Add one element.
764
766{
767 TBtItem newitem(k, t);
768 Add(newitem, at);
769}
770
771////////////////////////////////////////////////////////////////////////////////
772/// This should never create a full node that is, it is not used
773/// anywhere where THIS could possibly be near full.
774
776{
777 if (start > stop)
778 return;
779 R__ASSERT(0 <= start && start <= src->fLast);
780 R__ASSERT(0 <= stop && stop <= src->fLast );
781 R__ASSERT(fLast + stop - start + 1 < MaxIndex()); // full-node check
782 for (Int_t i = start; i <= stop; i++)
783 SetItem(++fLast, src->GetItem(i));
784}
785
786////////////////////////////////////////////////////////////////////////////////
787/// Never called from anywhere where it might fill up THIS.
788
790{
792 if (d) R__ASSERT(d->IsSortable());
793 SetItem(++fLast, d, n);
794}
795
796////////////////////////////////////////////////////////////////////////////////
797/// Append itm to this tree.
798
804
805////////////////////////////////////////////////////////////////////////////////
806/// THIS has more than LEFTSIB. Move some item from THIS to LEFTSIB.
807/// PIDX is the index of the parent item that will change when keys
808/// are moved.
809
818
819////////////////////////////////////////////////////////////////////////////////
820/// THIS has more than RIGHTSIB. Move some items from THIS to RIGHTSIB.
821/// PIDX is the index of the parent item that will change when keys
822/// are moved.
823
832
833////////////////////////////////////////////////////////////////////////////////
834/// PINDX is the index of the parent item whose key will change when
835/// keys are shifted from one InnerNode to the other.
836
838{
839 if (Psize() < rightsib->Vsize())
840 rightsib->BalanceWithLeft(this, pindx);
841 else
843}
844
845////////////////////////////////////////////////////////////////////////////////
846/// THAT is a child of THIS that has just shrunk by 1.
847
849{
850 Int_t i = IndexOf(that);
852 if (fParent)
853 fParent->DecrNofKeys(this);
854 else
856}
857
858////////////////////////////////////////////////////////////////////////////////
859/// Recursively look for WHAT starting in the current node.
860
862{
863 if (((TObject *)what)->Compare(GetKey(1)) < 0)
864 return GetTree(0)->FindRank(what);
865 Int_t sum = GetNofKeys(0);
866 for (Int_t i = 1; i < fLast; i++) {
867 if (((TObject*)what)->Compare(GetKey(i)) == 0)
868 return sum;
869 sum++;
870 if (((TObject *)what)->Compare(GetKey(i+1)) < 0)
871 return sum + GetTree(i)->FindRank(what);
872 sum += GetNofKeys(i);
873 }
874 if (((TObject*)what)->Compare(GetKey(fLast)) == 0)
875 return sum;
876 sum++;
877 // *what > GetKey(fLast), so recurse on last fItem.fTree
878 return sum + GetTree(fLast)->FindRank(what);
879}
880
881////////////////////////////////////////////////////////////////////////////////
882/// FindRankUp is FindRank in reverse.
883/// Whereas FindRank looks for the object and computes the rank
884/// along the way while walking DOWN the tree, FindRankUp already
885/// knows where the object is and has to walk UP the tree from the
886/// object to compute the rank.
887
889{
890 Int_t l = IndexOf(that);
891 Int_t sum = 0;
892 for (Int_t i = 0; i < l; i++)
893 sum += GetNofKeys(i);
894 return sum + l + (!fParent ? 0 : fParent->FindRankUp(this));
895}
896
897////////////////////////////////////////////////////////////////////////////////
898/// Return the first leaf node.
899
904
905////////////////////////////////////////////////////////////////////////////////
906/// Recursively look for WHAT starting in the current node.
907
909{
910 R__ASSERT(what->IsSortable());
911 for (Int_t i = 1 ; i <= fLast; i++) {
912 if (GetKey(i)->Compare(what) == 0) {
913 // then could go in either fItem[i].fTree or fItem[i-1].fTree
914 // should go in one with the most room, but that's kinda
915 // hard to calculate, so we'll stick it in fItem[i].fTree
916 *which = this;
917 *where = i;
918 return GetKey(i);
919 }
920 if (GetKey(i)->Compare(what) > 0)
921 return GetTree(i-1)->Found(what, which, where);
922 }
923 // *what > *(*this)[fLast].fKey, so recurse on last fItem.fTree
924 return GetTree(fLast)->Found(what, which, where);
925}
926
927////////////////////////////////////////////////////////////////////////////////
928/// THAT is a child of THIS that has just grown by 1.
929
931{
932 Int_t i = IndexOf(that);
934 if (fParent)
935 fParent->IncrNofKeys(this);
936 else
938}
939
940////////////////////////////////////////////////////////////////////////////////
941/// Returns a number in the range 0 to this->fLast
942/// 0 is returned if THAT == fTree[0].
943
945{
946 for (Int_t i = 0; i <= fLast; i++)
947 if (GetTree(i) == that)
948 return i;
949 R__CHECK(0);
950 return 0;
951}
952
953////////////////////////////////////////////////////////////////////////////////
954/// Tell the parent that we are full.
955
957{
958 if (!fParent) {
959 // then this is the root of the tree and needs to be split
960 // inform the btree.
961 R__ASSERT(fTree->fRoot == this);
962 fTree->RootIsFull();
963 } else
964 fParent->IsFull(this);
965}
966
967////////////////////////////////////////////////////////////////////////////////
968/// The child node THAT is full. We will either redistribute elements
969/// or create a new node and then redistribute.
970/// In an attempt to minimize the number of splits, we adopt the following
971/// strategy:
972/// - redistribute if possible
973/// - if not possible, then split with a sibling
974
976{
977 if (that->fIsLeaf) {
979 TBtLeafNode *left = nullptr;
980 TBtLeafNode *right= nullptr;
981 // split LEAF only if both sibling nodes are full.
984 ((right = (TBtLeafNode*)GetTree(leafidx+1)) != nullptr);
985 Int_t hasLeftSib = (leafidx > 0) &&
986 ((left = (TBtLeafNode*)GetTree(leafidx-1)) != nullptr);
989 if (rightSibFull) {
990 if (leftSibFull) {
991 // both full, so pick one to split with
992 left->SplitWith(leaf, leafidx);
993 } else if (hasLeftSib) {
994 // left sib not full, so balance with it
995 leaf->BalanceWithLeft(left, leafidx);
996 } else {
997 // there is no left sibling, so split with right
998 leaf->SplitWith(right, leafidx+1);
999 }
1000 } else if (hasRightSib) {
1001 // right sib not full, so balance with it
1002 leaf->BalanceWithRight(right, leafidx+1);
1003 } else if (leftSibFull) {
1004 // no right sib, and left sib is full, so split with it
1005 left->SplitWith(leaf, leafidx);
1006 } else if (hasLeftSib) {
1007 // left sib not full so balance with it
1008 leaf->BalanceWithLeft(left, leafidx);
1009 } else {
1010 // neither a left or right sib; should never happen
1011 R__CHECK(0);
1012 }
1013 } else {
1015 // split INNER only if both sibling nodes are full
1017 TBtInnerNode *left = nullptr;
1018 TBtInnerNode *right = nullptr;
1020 ((right = (TBtInnerNode*)GetTree(inneridx+1)) != nullptr);
1021 Int_t hasLeftSib = (inneridx > 0) &&
1022 ((left=(TBtInnerNode*)GetTree(inneridx-1)) != nullptr);
1025 if (rightSibFull) {
1026 if (leftSibFull) {
1027 left->SplitWith(inner, inneridx);
1028 } else if (hasLeftSib) {
1029 inner->BalanceWithLeft(left, inneridx);
1030 } else {
1031 // there is no left sibling
1032 inner->SplitWith(right, inneridx+1);
1033 }
1034 } else if (hasRightSib) {
1035 inner->BalanceWithRight(right, inneridx+1);
1036 } else if (leftSibFull) {
1037 left->SplitWith(inner, inneridx);
1038 } else if (hasLeftSib) {
1039 inner->BalanceWithLeft(left, inneridx);
1040 } else {
1041 R__CHECK(0);
1042 }
1043 }
1044}
1045
1046////////////////////////////////////////////////////////////////////////////////
1047/// The child node THAT is <= half full. We will either redistribute
1048/// elements between children, or THAT will be merged with another child.
1049/// In an attempt to minimize the number of mergers, we adopt the following
1050/// strategy:
1051/// - redistribute if possible
1052/// - if not possible, then merge with a sibling
1053
1055{
1056 if (that->fIsLeaf) {
1058 TBtLeafNode *left = nullptr;
1059 TBtLeafNode *right = nullptr;
1060 // split LEAF only if both sibling nodes are full.
1063 ((right = (TBtLeafNode*)GetTree(leafidx+1)) != nullptr);
1064 Int_t hasLeftSib = (leafidx > 0) &&
1065 ((left = (TBtLeafNode*)GetTree(leafidx-1)) != nullptr);
1066 if (hasRightSib && (leaf->Psize() + right->Vsize()) >= leaf->MaxPsize()) {
1067 // then cannot merge,
1068 // and balancing this and rightsib will leave them both
1069 // more than half full
1070 leaf->BalanceWith(right, leafidx+1);
1071 } else if (hasLeftSib && (leaf->Vsize() + left->Psize()) >= leaf->MaxPsize()) {
1072 // ditto
1073 left->BalanceWith(leaf, leafidx);
1074 } else if (hasLeftSib) {
1075 // then they should be merged
1076 left->MergeWithRight(leaf, leafidx);
1077 } else if (hasRightSib) {
1078 leaf->MergeWithRight(right, leafidx+1);
1079 } else {
1080 R__CHECK(0); // should never happen
1081 }
1082 } else {
1084
1086 TBtInnerNode *left = nullptr;
1087 TBtInnerNode *right = nullptr;
1089 ((right = (TBtInnerNode*)GetTree(inneridx+1)) != nullptr);
1090 Int_t hasLeftSib = (inneridx > 0) &&
1091 ((left = (TBtInnerNode*)GetTree(inneridx-1)) != nullptr);
1092 if (hasRightSib && (inner->Psize() + right->Vsize()) >= inner->MaxPsize()) {
1093 // cannot merge
1094 inner->BalanceWith(right, inneridx+1);
1095 } else if (hasLeftSib && (inner->Vsize() + left->Psize()) >= inner->MaxPsize()) {
1096 // cannot merge
1097 left->BalanceWith(inner, inneridx);
1098 } else if (hasLeftSib) {
1100 } else if (hasRightSib) {
1101 inner->MergeWithRight(right, inneridx+1);
1102 } else {
1103 R__CHECK(0);
1104 }
1105 }
1106}
1107
1108////////////////////////////////////////////////////////////////////////////////
1109/// Return the last leaf node.
1110
1115
1116////////////////////////////////////////////////////////////////////////////////
1117/// Merge the 2 part of the tree.
1118
1120{
1121 R__ASSERT(Psize() + rightsib->Vsize() < MaxIndex());
1122 if (rightsib->Psize() > 0)
1123 rightsib->PushLeft(rightsib->Psize(), this, pidx);
1124 rightsib->SetKey(0, fParent->GetKey(pidx));
1125 AppendFrom(rightsib, 0, 0);
1126 fParent->IncNofKeys(pidx-1, rightsib->GetNofKeys(0)+1);
1128 delete rightsib;
1129}
1130
1131////////////////////////////////////////////////////////////////////////////////
1132/// Number of key.
1133
1135{
1136 Int_t sum = 0;
1137 for (Int_t i = 0; i <= fLast; i++)
1138 sum += GetNofKeys(i);
1139 return sum + Psize();
1140}
1141
1142////////////////////////////////////////////////////////////////////////////////
1143/// return an element.
1144
1146{
1147 for (Int_t j = 0; j <= fLast; j++) {
1148 Int_t r;
1149 if (idx < (r = GetNofKeys(j)))
1150 return (*GetTree(j))[idx];
1151 if (idx == r) {
1152 if (j == fLast) {
1153 ::Error("TBtInnerNode::operator[]", "should not happen, 0 returned");
1154 return nullptr;
1155 } else
1156 return GetKey(j+1);
1157 }
1158 idx -= r+1; // +1 because of the key in the node
1159 }
1160 ::Error("TBtInnerNode::operator[]", "should not happen, 0 returned");
1161 return nullptr;
1162}
1163
1164////////////////////////////////////////////////////////////////////////////////
1165/// noFromThis==1 => moves the parent item into the leftsib,
1166/// and the first item in this's array into the parent item.
1167
1169{
1170 R__ASSERT(fParent->GetTree(pidx) == this);
1171 R__ASSERT(noFromThis > 0 && noFromThis <= Psize());
1172 R__ASSERT(noFromThis + leftsib->Psize() < MaxPsize());
1173 SetKey(0, fParent->GetKey(pidx)); // makes AppendFrom's job easier
1174 leftsib->AppendFrom(this, 0, noFromThis-1);
1176 fParent->SetKey(pidx, GetKey(0));
1177 fParent->SetNofKeys(pidx-1, leftsib->NofKeys());
1179}
1180
1181////////////////////////////////////////////////////////////////////////////////
1182/// The operation is three steps:
1183/// - Step I. Make room for the incoming keys in RIGHTSIB.
1184/// - Step II. Move the items from THIS into RIGHTSIB.
1185/// - Step III. Update the length of THIS.
1186
1188{
1189 R__ASSERT(noFromThis > 0 && noFromThis <= Psize());
1190 R__ASSERT(noFromThis + rightsib->Psize() < rightsib->MaxPsize());
1192
1193 //
1194 // Step I. Make space for noFromThis items
1195 //
1196 Int_t start = fLast - noFromThis + 1;
1197 Int_t tgt, src;
1198 tgt = rightsib->fLast + noFromThis;
1199 src = rightsib->fLast;
1200 rightsib->fLast = tgt;
1201 rightsib->SetKey(0, fParent->GetKey(pidx));
1202 IncNofKeys(0);
1203 while (src >= 0) {
1204 // do this kind of assignment on TBtInnerNode items only when
1205 // the parent fields of the moved items do not change, as they
1206 // don't here.
1207 // Otherwise, use SetItem so the parents are updated appropriately.
1208 rightsib->GetItem(tgt--) = rightsib->GetItem(src--);
1209 }
1210
1211 // Step II. Move the items from THIS into RIGHTSIB
1212 for (Int_t i = fLast; i >= start; i-- ) {
1213 // this is the kind of assignment to use when parents change
1214 rightsib->SetItem(tgt--, GetItem(i));
1215 }
1216 fParent->SetKey(pidx, rightsib->GetKey(0));
1217 DecNofKeys(0);
1218 R__CHECK(tgt == -1);
1219
1220 // Step III.
1221 fLast -= noFromThis;
1222
1223 // Step VI. update NofKeys
1225 fParent->SetNofKeys(pidx, rightsib->NofKeys());
1226}
1227
1228////////////////////////////////////////////////////////////////////////////////
1229/// Remove an element.
1230
1232{
1233 R__ASSERT(index >= 1 && index <= fLast);
1235 SetKey(index, lf->fItem[0]);
1236 lf->RemoveItem(0);
1237}
1238
1239////////////////////////////////////////////////////////////////////////////////
1240/// Remove an item.
1241
1243{
1244 R__ASSERT(index >= 1 && index <= fLast);
1245 for (Int_t to = index; to < fLast; to++)
1246 fItem[to] = fItem[to+1];
1247 fLast--;
1248 if (IsLow()) {
1249 if (!fParent) {
1250 // then this is the root; when only one child, make the child the root
1251 if (Psize() == 0)
1252 fTree->RootIsEmpty();
1253 } else
1254 fParent->IsLow(this);
1255 }
1256}
1257
1258////////////////////////////////////////////////////////////////////////////////
1259/// Shift to the left.
1260
1262{
1263 if (cnt <= 0)
1264 return;
1265 for (Int_t i = cnt; i <= fLast; i++)
1266 GetItem(i-cnt) = GetItem(i);
1267 fLast -= cnt;
1268}
1269
1270////////////////////////////////////////////////////////////////////////////////
1271/// This function is called only when THIS is the only descendent
1272/// of the root node, and THIS needs to be split.
1273/// Assumes that idx of THIS in fParent is 0.
1274
1276{
1278 R__CHECK(newnode != nullptr);
1280 newnode->AppendFrom(this, fLast, fLast);
1281 fLast--;
1282 fParent->IncNofKeys(1, newnode->GetNofKeys(0));
1283 fParent->DecNofKeys(0, newnode->GetNofKeys(0));
1285}
1286
1287////////////////////////////////////////////////////////////////////////////////
1288/// THIS and SIB are too full; create a NEWNODE, and balance
1289/// the number of keys between the three of them.
1290///
1291/// picture: (also see Knuth Vol 3 pg 478)
1292/// ~~~ {.cpp}
1293/// keyidx keyidx+1
1294/// +--+--+--+--+--+--...
1295/// | | | | | |
1296/// fParent--->| | | |
1297/// | | | |
1298/// +*-+*-+*-+--+--+--...
1299/// | | |
1300/// +----+ | +-----+
1301/// | +-----+ |
1302/// V | V
1303/// +----------+ | +----------+
1304/// | | | | |
1305/// this->| | | | |<--sib
1306/// +----------+ | +----------+
1307/// V
1308/// data
1309/// ~~~
1310/// keyidx is the index of where the sibling is, and where the
1311/// newly created node will be recorded (sibling will be moved to
1312/// keyidx+1)
1313
1315{
1317
1318 rightsib->SetKey(0, fParent->GetKey(keyidx));
1319 Int_t nofKeys = Psize() + rightsib->Vsize();
1324 Int_t noFromSib = rightsib->Vsize() - newSizeSib;
1325 // because of their smaller size, this TBtInnerNode may not have to
1326 // give up any elements to the new node. I.e., noFromThis == 0.
1327 // This will not happen for TBtLeafNodes.
1328 // We handle this by pulling an item from the rightsib.
1329 R__CHECK(noFromThis >= 0);
1330 R__CHECK(noFromSib >= 1);
1332 R__CHECK(newNode != nullptr);
1333 if (noFromThis > 0) {
1334 newNode->Append(GetItem(fLast));
1336 if (noFromThis > 2)
1337 this->PushRight(noFromThis-1, newNode, keyidx);
1338 rightsib->PushLeft(noFromSib, newNode, keyidx+1);
1339 } else {
1340 // pull an element from the rightsib
1341 newNode->Append(rightsib->GetItem(0));
1342 fParent->AddElt(keyidx+1, rightsib->GetKey(1), rightsib);
1343 rightsib->ShiftLeft(1);
1345 rightsib->PushLeft(noFromSib-1, newNode, keyidx+1);
1346 }
1347 fParent->SetNofKeys(keyidx-1, this->NofKeys());
1348 fParent->SetNofKeys(keyidx, newNode->NofKeys());
1349 fParent->SetNofKeys(keyidx+1, rightsib->NofKeys());
1350 if (fParent->IsFull())
1352}
1353
1354/** \class TBtLeafNode
1355Leaf node of a TBtree.
1356*/
1357
1358////////////////////////////////////////////////////////////////////////////////
1359/// Constructor.
1360
1362{
1363 fItem = new TObject *[MaxIndex()+1];
1364 memset(fItem, 0, (MaxIndex()+1)*sizeof(TObject*));
1365
1366 R__ASSERT(fItem != nullptr);
1367 if (obj)
1368 fItem[++fLast] = (TObject*)obj; // cast const away
1369}
1370
1371////////////////////////////////////////////////////////////////////////////////
1372/// Destructor.
1373
1375{
1376 delete [] fItem;
1377}
1378
1379////////////////////////////////////////////////////////////////////////////////
1380/// Add the object OBJ to the leaf node, inserting it at location INDEX
1381/// in the fItem array.
1382
1384{
1385 R__ASSERT(obj->IsSortable());
1386 R__ASSERT(0 <= index && index <= fLast+1);
1387 R__ASSERT(fLast <= MaxIndex());
1388 for (Int_t i = fLast+1; i > index ; i--)
1389 fItem[i] = fItem[i-1];
1390 fItem[index] = (TObject *)obj;
1391 fLast++;
1392
1393 // check for overflow
1394 if (!fParent)
1395 fTree->IncrNofKeys();
1396 else
1397 fParent->IncrNofKeys(this);
1398
1399 if (IsFull()) {
1400 // it's full; tell parent node
1401 if (!fParent) {
1402 // this occurs when this leaf is the only node in the
1403 // btree, and this->fTree->fRoot == this
1404 R__CHECK(fTree->fRoot == this);
1405 // in which case we inform the btree, which can be
1406 // considered the parent of this node
1407 fTree->RootIsFull();
1408 } else {
1409 // the parent is responsible for splitting/balancing subnodes
1410 fParent->IsFull(this);
1411 }
1412 }
1413}
1414
1415////////////////////////////////////////////////////////////////////////////////
1416/// A convenience function, does not worry about the element in
1417/// the parent, simply moves elements from SRC[start] to SRC[stop]
1418/// into the current array.
1419/// This should never create a full node.
1420/// That is, it is not used anywhere where THIS could possibly be
1421/// near full.
1422/// Does NOT handle nofKeys.
1423
1425{
1426 if (start > stop)
1427 return;
1428 R__ASSERT(0 <= start && start <= src->fLast);
1429 R__ASSERT(0 <= stop && stop <= src->fLast);
1430 R__ASSERT(fLast + stop - start + 1 < MaxIndex()); // full-node check
1431 for (Int_t i = start; i <= stop; i++)
1432 fItem[++fLast] = src->fItem[i];
1433 R__CHECK(fLast < MaxIndex());
1434}
1435
1436////////////////////////////////////////////////////////////////////////////////
1437/// Never called from anywhere where it might fill up THIS
1438/// does NOT handle nofKeys.
1439
1441{
1442 R__ASSERT(obj->IsSortable());
1443 fItem[++fLast] = obj;
1444 R__CHECK(fLast < MaxIndex());
1445}
1446
1447////////////////////////////////////////////////////////////////////////////////
1448/// THIS has more than LEFTSIB; move some items from THIS to LEFTSIB.
1449
1457
1458////////////////////////////////////////////////////////////////////////////////
1459/// THIS has more than RIGHTSIB; move some items from THIS to RIGHTSIB.
1460
1468
1469////////////////////////////////////////////////////////////////////////////////
1470/// PITEM is the parent item whose key will change when keys are shifted
1471/// from one LeafNode to the other.
1472
1474{
1475 if (Psize() < rightsib->Vsize())
1476 rightsib->BalanceWithLeft(this, pidx);
1477 else
1479}
1480
1481////////////////////////////////////////////////////////////////////////////////
1482/// WHAT was not in any inner node; it is either here, or it's
1483/// not in the tree.
1484
1486{
1487 for (Int_t i = 0; i <= fLast; i++) {
1488 if (fItem[i]->Compare(what) == 0)
1489 return i;
1490 if (fItem[i]->Compare(what) > 0)
1491 return -1;
1492 }
1493 return -1;
1494}
1495
1496////////////////////////////////////////////////////////////////////////////////
1497/// Return the first node.
1498
1500{
1501 return this;
1502}
1503
1504////////////////////////////////////////////////////////////////////////////////
1505/// WHAT was not in any inner node; it is either here, or it's
1506/// not in the tree.
1507
1509{
1510 R__ASSERT(what->IsSortable());
1511 for (Int_t i = 0; i <= fLast; i++) {
1512 if (fItem[i]->Compare(what) == 0) {
1513 *which = this;
1514 *where = i;
1515 return fItem[i];
1516 }
1517 if (fItem[i]->Compare(what) > 0) {
1518 *which = this;
1519 *where = i;
1520 return nullptr;
1521 }
1522 }
1523 *which = this;
1524 *where = fLast+1;
1525 return nullptr;
1526}
1527
1528////////////////////////////////////////////////////////////////////////////////
1529/// Returns a number in the range 0 to MaxIndex().
1530
1532{
1533 for (Int_t i = 0; i <= fLast; i++) {
1534 if (fItem[i] == that)
1535 return i;
1536 }
1537 R__CHECK(0);
1538 return -1;
1539}
1540
1541////////////////////////////////////////////////////////////////////////////////
1542/// return the last node.
1543
1545{
1546 return this;
1547}
1548
1549////////////////////////////////////////////////////////////////////////////////
1550/// Merge.
1551
1553{
1554 R__ASSERT(Psize() + rightsib->Vsize() < MaxPsize());
1555 rightsib->PushLeft(rightsib->Psize(), this, pidx);
1559 delete rightsib;
1560}
1561
1562////////////////////////////////////////////////////////////////////////////////
1563/// Return the number of keys.
1564
1566{
1567 return 1;
1568}
1569
1570////////////////////////////////////////////////////////////////////////////////
1571/// Return the number of keys.
1572
1574{
1575 return Psize();
1576}
1577
1578//______________________________________________________________________________
1579//void TBtLeafNode::PrintOn(std::ostream& out) const
1580//{
1581// out << " < ";
1582// for (Int_t i = 0; i <= fLast; i++)
1583// out << *fItem[i] << " " ;
1584// out << "> ";
1585//}
1586
1587////////////////////////////////////////////////////////////////////////////////
1588/// noFromThis==1 => moves the parent item into the leftsib,
1589/// and the first item in this's array into the parent item.
1590
1592{
1593 R__ASSERT(noFromThis > 0 && noFromThis <= Psize());
1594 R__ASSERT(noFromThis + leftsib->Psize() < MaxPsize());
1595 R__ASSERT(fParent->GetTree(pidx) == this);
1596 leftsib->Append(fParent->GetKey(pidx));
1597 if (noFromThis > 1)
1598 leftsib->AppendFrom(this, 0, noFromThis-2);
1601 fParent->SetNofKeys(pidx-1, leftsib->NofKeys());
1603}
1604
1605////////////////////////////////////////////////////////////////////////////////
1606/// noFromThis==1 => moves the parent item into the
1607/// rightsib, and the last item in this's array into the parent
1608/// item.
1609
1611{
1612 R__ASSERT(noFromThis > 0 && noFromThis <= Psize());
1613 R__ASSERT(noFromThis + rightsib->Psize() < MaxPsize());
1615 // The operation is five steps:
1616 // Step I. Make room for the incoming keys in RIGHTSIB.
1617 // Step II. Move the key in the parent into RIGHTSIB.
1618 // Step III. Move the items from THIS into RIGHTSIB.
1619 // Step IV. Move the item from THIS into the parent.
1620 // Step V. Update the length of THIS.
1621 //
1622 // Step I.: make space for noFromThis items
1623 //
1624 Int_t start = fLast - noFromThis + 1;
1625 Int_t tgt, src;
1626 tgt = rightsib->fLast + noFromThis;
1627 src = rightsib->fLast;
1628 rightsib->fLast = tgt;
1629 while (src >= 0)
1630 rightsib->fItem[tgt--] = rightsib->fItem[src--];
1631
1632 // Step II. Move the key from the parent into place
1633 rightsib->fItem[tgt--] = fParent->GetKey(pidx);
1634
1635 // Step III.Move the items from THIS into RIGHTSIB
1636 for (Int_t i = fLast; i > start; i--)
1637 rightsib->fItem[tgt--] = fItem[i];
1638 R__CHECK(tgt == -1);
1639
1640 // Step IV.
1641 fParent->SetKey(pidx, fItem[start]);
1642
1643 // Step V.
1644 fLast -= noFromThis;
1645
1646 // Step VI. update nofKeys
1648 fParent->SetNofKeys(pidx, rightsib->NofKeys());
1649}
1650
1651////////////////////////////////////////////////////////////////////////////////
1652/// Remove an element.
1653
1655{
1656 R__ASSERT(index >= 0 && index <= fLast);
1657 for (Int_t to = index; to < fLast; to++)
1658 fItem[to] = fItem[to+1];
1659 fLast--;
1660 if (!fParent)
1661 fTree->DecrNofKeys();
1662 else
1663 fParent->DecrNofKeys(this);
1664 if (IsLow()) {
1665 if (!fParent) {
1666 // then this is the root; when no keys left, inform the tree
1667 if (Psize() == 0)
1668 fTree->RootIsEmpty();
1669 } else
1670 fParent->IsLow(this);
1671 }
1672}
1673
1674////////////////////////////////////////////////////////////////////////////////
1675/// Shift.
1676
1678{
1679 if (cnt <= 0)
1680 return;
1681 for (Int_t i = cnt; i <= fLast; i++)
1682 fItem[i-cnt] = fItem[i];
1683 fLast -= cnt;
1684}
1685
1686////////////////////////////////////////////////////////////////////////////////
1687/// This function is called only when THIS is the only descendent
1688/// of the root node, and THIS needs to be split.
1689/// Assumes that idx of THIS in Parent is 0.
1690
1700
1701////////////////////////////////////////////////////////////////////////////////
1702/// Split.
1703
1705{
1706 R__ASSERT(fParent == rightsib->fParent);
1708 Int_t nofKeys = Psize() + rightsib->Vsize();
1713 Int_t noFromSib = rightsib->Vsize() - newSizeSib;
1714 R__CHECK(noFromThis >= 0);
1715 R__CHECK(noFromSib >= 1);
1717 R__ASSERT(newNode != nullptr);
1721 this->PushRight(noFromThis-1, newNode, keyidx);
1722 rightsib->PushLeft(noFromSib, newNode, keyidx+1);
1723 if (fParent->IsFull())
1725}
#define SafeDelete(p)
Definition RConfig.hxx:533
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
const Bool_t kIterForward
Definition TCollection.h:42
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:208
void Fatal(const char *location, const char *msgfmt,...)
Use this function in case of a fatal error. It will abort the program.
Definition TError.cxx:267
#define R__CHECK(e)
Checks condition e and reports a warning message if it's false.
Definition TError.h:134
Int_t Compare(const void *item1, const void *item2)
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
char name[80]
Definition TGX11.cxx:110
Inner node of a TBtree.
Definition TBtree.h:184
Int_t DecNofKeys(Int_t i, Int_t n=1)
Definition TBtree.h:407
void InformParent()
Tell the parent that we are full.
Definition TBtree.cxx:956
void ShiftLeft(Int_t cnt)
Shift to the left.
Definition TBtree.cxx:1261
Int_t NofKeys() const override
Number of key.
Definition TBtree.cxx:1134
void BalanceWithLeft(TBtInnerNode *l, Int_t idx)
THIS has more than LEFTSIB.
Definition TBtree.cxx:810
Int_t IncNofKeys(Int_t i, Int_t n=1)
Definition TBtree.h:402
void BalanceWithRight(TBtInnerNode *r, Int_t idx)
THIS has more than RIGHTSIB.
Definition TBtree.cxx:824
Int_t FindRankUp(const TBtNode *n) const
FindRankUp is FindRank in reverse.
Definition TBtree.cxx:888
void AppendFrom(TBtInnerNode *src, Int_t start, Int_t stop)
This should never create a full node that is, it is not used anywhere where THIS could possibly be ne...
Definition TBtree.cxx:775
void Append(TObject *obj, TBtNode *n)
Never called from anywhere where it might fill up THIS.
Definition TBtree.cxx:789
Int_t IsFull() const
Definition TBtree.h:250
TBtItem & GetItem(Int_t i) const
Definition TBtree.h:219
void SetKey(Int_t i, TObject *obj)
Definition TBtree.h:208
Int_t GetNofKeys(Int_t i) const
Definition TBtree.h:386
void AddElt(TBtItem &itm, Int_t at)
Add one element.
Definition TBtree.cxx:733
Int_t MaxIndex() const
Definition TBtree.h:245
Int_t Vsize() const
Definition TBtree.h:412
Int_t IndexOf(const TBtNode *n) const
Returns a number in the range 0 to this->fLast 0 is returned if THAT == fTree[0].
Definition TBtree.cxx:944
Int_t FindRank(const TObject *obj) const override
Recursively look for WHAT starting in the current node.
Definition TBtree.cxx:861
void Add(const TObject *obj, Int_t idx) override
This is called only from TBtree::Add().
Definition TBtree.cxx:723
void MergeWithRight(TBtInnerNode *r, Int_t idx)
Merge the 2 part of the tree.
Definition TBtree.cxx:1119
Int_t IsAlmostFull() const
Definition TBtree.h:252
void SetItem(Int_t i, TBtItem &itm)
Definition TBtree.h:209
void SetNofKeys(Int_t i, Int_t r)
Definition TBtree.h:397
Int_t MaxPsize() const
Definition TBtree.h:246
void SetTree(Int_t i, TBtNode *node)
Definition TBtree.h:207
void PushLeft(Int_t cnt, TBtInnerNode *leftsib, Int_t parentIdx)
noFromThis==1 => moves the parent item into the leftsib, and the first item in this's array into the ...
Definition TBtree.cxx:1168
void IncrNofKeys(TBtNode *np)
THAT is a child of THIS that has just grown by 1.
Definition TBtree.cxx:930
TObject * GetKey(Int_t i) const
Definition TBtree.h:218
void DecrNofKeys(TBtNode *np)
THAT is a child of THIS that has just shrunk by 1.
Definition TBtree.cxx:848
void Remove(Int_t idx) override
Remove an element.
Definition TBtree.cxx:1231
~TBtInnerNode()
Constructor.
Definition TBtree.cxx:710
void BalanceWith(TBtInnerNode *n, int idx)
PINDX is the index of the parent item whose key will change when keys are shifted from one InnerNode ...
Definition TBtree.cxx:837
void Split() override
This function is called only when THIS is the only descendent of the root node, and THIS needs to be ...
Definition TBtree.cxx:1275
void PushRight(Int_t cnt, TBtInnerNode *rightsib, Int_t parentIdx)
The operation is three steps:
Definition TBtree.cxx:1187
TObject * operator[](Int_t i) const override
return an element.
Definition TBtree.cxx:1145
TBtNode * GetTree(Int_t i) const
Definition TBtree.h:217
void SplitWith(TBtInnerNode *r, Int_t idx)
THIS and SIB are too full; create a NEWNODE, and balance the number of keys between the three of them...
Definition TBtree.cxx:1314
void RemoveItem(Int_t idx)
Remove an item.
Definition TBtree.cxx:1242
TBtItem * fItem
Definition TBtree.h:187
TBtLeafNode * FirstLeafNode() override
Return the first leaf node.
Definition TBtree.cxx:900
TObject * Found(const TObject *obj, TBtNode **which, Int_t *where) override
Recursively look for WHAT starting in the current node.
Definition TBtree.cxx:908
Int_t IsLow() const
Definition TBtree.h:253
TBtLeafNode * LastLeafNode() override
Return the last leaf node.
Definition TBtree.cxx:1111
Int_t Psize() const
Definition TBtree.h:243
Item stored in inner nodes of a TBtree.
Definition TBtree.h:159
TBtItem()
sub-tree
Definition TBtree.cxx:495
~TBtItem()
Delete a tree item.
Definition TBtree.cxx:529
TObject * fKey
Definition TBtree.h:165
Int_t fNofKeysInTree
Definition TBtree.h:164
TBtNode * fTree
Definition TBtree.h:166
Leaf node of a TBtree.
Definition TBtree.h:266
void BalanceWith(TBtLeafNode *n, Int_t idx)
PITEM is the parent item whose key will change when keys are shifted from one LeafNode to the other.
Definition TBtree.cxx:1473
void BalanceWithRight(TBtLeafNode *r, Int_t idx)
THIS has more than RIGHTSIB; move some items from THIS to RIGHTSIB.
Definition TBtree.cxx:1461
Int_t Vsize() const
Definition TBtree.h:427
void Split() override
This function is called only when THIS is the only descendent of the root node, and THIS needs to be ...
Definition TBtree.cxx:1691
Int_t IsAlmostFull() const
Definition TBtree.h:315
Int_t Psize() const
Definition TBtree.h:307
TObject ** fItem
Definition TBtree.h:271
void ShiftLeft(Int_t cnt)
Shift.
Definition TBtree.cxx:1677
void PushRight(Int_t cnt, TBtLeafNode *r, Int_t parentIndex)
noFromThis==1 => moves the parent item into the rightsib, and the last item in this's array into the ...
Definition TBtree.cxx:1610
Int_t MaxPsize() const
Definition TBtree.h:310
void SplitWith(TBtLeafNode *r, Int_t idx)
Split.
Definition TBtree.cxx:1704
TObject * Found(const TObject *obj, TBtNode **which, Int_t *where) override
WHAT was not in any inner node; it is either here, or it's not in the tree.
Definition TBtree.cxx:1508
TBtLeafNode * FirstLeafNode() override
Return the first node.
Definition TBtree.cxx:1499
void Remove(Int_t idx) override
Remove an element.
Definition TBtree.cxx:1654
void BalanceWithLeft(TBtLeafNode *l, Int_t idx)
THIS has more than LEFTSIB; move some items from THIS to LEFTSIB.
Definition TBtree.cxx:1450
void PushLeft(Int_t cnt, TBtLeafNode *l, Int_t parentIndex)
noFromThis==1 => moves the parent item into the leftsib, and the first item in this's array into the ...
Definition TBtree.cxx:1591
void Add(const TObject *obj, Int_t idx) override
Add the object OBJ to the leaf node, inserting it at location INDEX in the fItem array.
Definition TBtree.cxx:1383
void MergeWithRight(TBtLeafNode *r, Int_t idx)
Merge.
Definition TBtree.cxx:1552
~TBtLeafNode()
Destructor.
Definition TBtree.cxx:1374
Int_t NofKeys() const override
Return the number of keys.
Definition TBtree.cxx:1573
Int_t MaxIndex() const
Definition TBtree.h:309
TBtLeafNode * LastLeafNode() override
return the last node.
Definition TBtree.cxx:1544
Int_t IsLow() const
Definition TBtree.h:316
void Append(TObject *obj)
Never called from anywhere where it might fill up THIS does NOT handle nofKeys.
Definition TBtree.cxx:1440
Int_t IsFull() const
Definition TBtree.h:314
Int_t FindRank(const TObject *obj) const override
WHAT was not in any inner node; it is either here, or it's not in the tree.
Definition TBtree.cxx:1485
Int_t IndexOf(const TObject *obj) const
Returns a number in the range 0 to MaxIndex().
Definition TBtree.cxx:1531
void AppendFrom(TBtLeafNode *src, Int_t start, Int_t stop)
A convenience function, does not worry about the element in the parent, simply moves elements from SR...
Definition TBtree.cxx:1424
Abstract base class (ABC) of a TBtree node.
Definition TBtree.h:112
virtual TBtLeafNode * LastLeafNode()=0
virtual Int_t FindRank(const TObject *obj) const =0
virtual ~TBtNode()
Delete a B-tree node.
Definition TBtree.cxx:563
virtual Int_t NofKeys() const =0
friend class TBtLeafNode
Definition TBtree.h:116
TBtNode(Int_t isleaf, TBtInnerNode *p, TBtree *t=nullptr)
Create a B-tree node.
Definition TBtree.cxx:540
TBtInnerNode * fParent
Definition TBtree.h:124
friend class TBtInnerNode
Definition TBtree.h:115
TBtree * fTree
Definition TBtree.h:125
Int_t fIsLeaf
Definition TBtree.h:126
Int_t fLast
Definition TBtree.h:119
virtual TBtLeafNode * FirstLeafNode()=0
virtual TObject * Found(const TObject *obj, TBtNode **which, Int_t *where)=0
Iterator of btree.
Definition TBtree.h:328
const TBtree * fTree
Definition TBtree.h:331
TBtreeIter()
Definition TBtree.h:336
Int_t fCurCursor
Definition TBtree.h:332
Bool_t operator!=(const TIterator &aIter) const override
This operator compares two TIterator objects.
Definition TBtree.cxx:653
static TClass * Class()
TIterator & operator=(const TIterator &rhs) override
Overridden assignment operator.
Definition TBtree.cxx:595
Bool_t fDirection
Definition TBtree.h:334
TObject * Next() override
Get next object from B-tree. Returns 0 when no more objects in tree.
Definition TBtree.cxx:637
void Reset() override
Reset the B-tree iterator.
Definition TBtree.cxx:624
Int_t fCursor
Definition TBtree.h:333
TObject * operator*() const override
Return current object or nullptr.
Definition TBtree.cxx:673
B-tree class.
Definition TBtree.h:38
Int_t fOrder
Definition TBtree.h:47
Int_t fInnerMaxIndex
Definition TBtree.h:52
Int_t IdxAdd(const TObject &obj)
Add object and return its index in the tree.
Definition TBtree.cxx:300
Int_t Rank(const TObject *obj) const
Returns the rank of the object in the tree.
Definition TBtree.cxx:392
TClass * IsA() const override
Definition TBtree.h:100
void Delete(Option_t *option="") override
Remove all objects from B-tree AND delete all heap based objects.
Definition TBtree.cxx:259
virtual ~TBtree()
Delete B-tree.
Definition TBtree.cxx:188
void Init(Int_t i)
Initialize a B-tree.
Definition TBtree.cxx:343
void DecrNofKeys()
Definition TBtree.h:61
friend class TBtLeafNode
Definition TBtree.h:42
TBtNode * fRoot
Definition TBtree.h:45
Int_t fLeafLowWaterMark
Definition TBtree.h:51
Int_t fLeafMaxIndex
Definition TBtree.h:53
TObject * Before(const TObject *obj) const override
May not use this method since B-tree decides order.
Definition TBtree.cxx:236
friend class TBtInnerNode
Definition TBtree.h:41
TObject * Remove(TObject *obj) override
Remove an object from the tree.
Definition TBtree.cxx:407
void RootIsFull()
The root of the tree is full.
Definition TBtree.cxx:429
TBtree(Int_t ordern=3)
Create a B-tree of certain order (by default 3).
Definition TBtree.cxx:179
void Add(TObject *obj) override
Add object to B-tree.
Definition TBtree.cxx:199
void Clear(Option_t *option="") override
Remove all objects from B-tree.
Definition TBtree.cxx:246
void Streamer(TBuffer &) override
Stream all objects in the btree to or from the I/O buffer.
Definition TBtree.cxx:459
TObject * After(const TObject *obj) const override
Cannot use this method since B-tree decides order.
Definition TBtree.cxx:227
Int_t fOrder2
Definition TBtree.h:48
TIterator * MakeIterator(Bool_t dir=kIterForward) const override
Returns a B-tree iterator.
Definition TBtree.cxx:384
void RootIsEmpty()
If root is empty clean up its space.
Definition TBtree.cxx:440
Int_t fInnerLowWaterMark
Definition TBtree.h:50
TObject * At(Int_t idx) const override
Definition TBtree.h:369
TObject * FindObject(const char *name) const override
Find object using its name (see object's GetName()).
Definition TBtree.cxx:274
void IncrNofKeys()
Definition TBtree.h:60
Buffer base class used for serializing objects.
Definition TBuffer.h:43
Bool_t IsArgNull(const char *where, const TObject *obj) const
Returns true if object is a null pointer.
Bool_t IsOwner() const
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
static void GarbageCollect(TObject *obj)
Add to the list of things to be cleaned up.
Iterator abstract base class.
Definition TIterator.h:30
Mother of all ROOT objects.
Definition TObject.h:41
virtual Bool_t IsSortable() const
Definition TObject.h:156
R__ALWAYS_INLINE Bool_t IsOnHeap() const
Definition TObject.h:158
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1057
void MayNotUse(const char *method) const
Use this method to signal that a method (defined in a base class) may not be called in a derived clas...
Definition TObject.cxx:1133
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
void Streamer(TBuffer &) override
Stream all objects in the collection to or from the I/O buffer.
const Int_t n
Definition legend1.C:16
static const char * what
Definition stlLoader.cc:5
TLine l
Definition textangle.C:4
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2339