/*------------------------------------------------------------------------*/ /* */ /* BTREELFN.CPP */ /* */ /* Copyright Borland International 1991, 1993 */ /* All Rights Reserved */ /* */ /*------------------------------------------------------------------------*/ #if !defined( __STDLIB_H ) #include #endif // __STDLIB_H #if !defined( __IOSTREAM_H ) #include #endif // __IOSTREAM_H #if !defined( CHECKS_H ) #include #endif // CHECKS_H #if !defined( __BTREE_H ) #include "classlib\obsolete\btree.h" #endif // __BTREE_H //====== LeafNode functions ======= LeafNode::LeafNode(InnerNode* P, Sortable* O, Btree* T): Node(1, P, T) { item = new Sortable *[maxIndex()+1]; if( item == 0 ) ClassLib_error( __ENOMEMLN ); if( O != 0 ) item[++last] = O; } LeafNode::~LeafNode() { if( tree->ownsElements() ) { for( int i = 0; i <= last; i++ ) delete item[i]; } delete [] item; } void LeafNode::add(Sortable *obj, int index) { // add the object OBJ to the leaf node, inserting it at location INDEX // in the item array PRECONDITION( 0 <= index && index <= last+1 ); PRECONDITION( last <= maxIndex() ); for( int i = last+1; i > index ; i-- ) item[i] = item[ i - 1 ]; item[ index ] = obj; last++; // check for overflow if( parent == 0 ) tree->incrNofKeys( ); else parent->incrNofKeys( this ); if( isFull() ) { // it's full; tell parent node if( parent == 0 ) { // this occurs when this leaf is the only node in the // btree, and this->tree->root == this CHECK( tree->root == this ); // in which case we inform the btree, which can be // considered the parent of this node tree->rootIsFull(); } else { // the parent is responsible for splitting/balancing subnodes parent->isFull( this ); } } } void LeafNode::appendFrom( LeafNode* src, int start, int stop ) { // A convenience function, does not worry about the element in // the parent, simply moves elements from SRC[start] to SRC[stop] // into the current array. // This should never create a full node. // That is, it is not used anywhere where THIS could possibly be // near full. // Does NOT handle nofKeys. if( start > stop ) return; PRECONDITION( 0 <= start && start <= src->last ); PRECONDITION( 0 <= stop && stop <= src->last ); PRECONDITION( last + stop - start + 1 < maxIndex() ); // full-node check for( int i = start; i <= stop; i++ ) item[++last] = src->item[i]; CHECK( last < maxIndex() ); } void LeafNode::append( Sortable* D ) { // never called from anywhere where it might fill up THIS // does NOT handle nofKeys. item[++last] = D; CHECK( last < maxIndex() ); } void LeafNode::balanceWithLeft( LeafNode* leftsib, int pidx ) { // THIS has more than LEFTSIB; move some items from THIS to LEFTSIB. PRECONDITION( Vsize() >= leftsib->Psize() ); int newThisSize = (Vsize() + leftsib->Psize())/2; int noFromThis = Psize() - newThisSize; pushLeft( noFromThis, leftsib, pidx ); } void LeafNode::balanceWithRight( LeafNode* rightsib, int pidx ) { // THIS has more than RIGHTSIB; move some items from THIS to RIGHTSIB. PRECONDITION( Psize() >= rightsib->Vsize() ); int newThisSize = (Psize() + rightsib->Vsize())/2; int noFromThis = Psize() - newThisSize; pushRight( noFromThis, rightsib, pidx ); } void LeafNode::balanceWith( LeafNode* rightsib, int pidx ) { // PITEM is the parent item whose key will change when keys are shifted // from one LeafNode to the other. if( Psize() < rightsib->Vsize() ) rightsib->balanceWithLeft( this, pidx ); else balanceWithRight( rightsib, pidx ); } long LeafNode::findRank( Sortable* what ) const { // WHAT was not in any inner node; it is either here, or it's // not in the tree for( int i = 0; i <= last; i++ ) { if( *item[i] == *what ) return i; if( *item[i] >= *what ) return -1; } return -1; } LeafNode *LeafNode::firstLeafNode() { return this; } Object& LeafNode::found(Sortable* what, Node** which, int* where ) { // WHAT was not in any inner node; it is either here, or it's // not in the tree for( int i = 0; i <= last; i++ ) { if( *item[i] == *what ) { *which = this; *where = i; return *item[i]; } if( *item[i] >= *what ) { *which = this; *where = i; return NOOBJECT; } } *which = this; *where = last+1; return NOOBJECT; } #pragma warn -rvl int LeafNode::indexOf( const Sortable *that ) const { // returns a number in the range 0 to maxIndex() for( int i = 0; i <= last; i++ ) { if( item[i] == that ) return i; } CHECK(0); } #pragma warn .rvl LeafNode *LeafNode::lastLeafNode() { return this; } void LeafNode::mergeWithRight( LeafNode* rightsib, int pidx ) { PRECONDITION( Psize() + rightsib->Vsize() < maxPsize() ); rightsib->pushLeft( rightsib->Psize(), this, pidx ); append( parent->getKey( pidx ) ); parent->setNofKeys( pidx-1, nofKeys() ); // cout << "in mergeWithRight:\n" << *parent << "\n"; parent->removeItem( pidx ); delete rightsib; // cout << "in mergeWithRight:\n" << *parent << "\n"; } long LeafNode::nofKeys( int ) const { return 1; } long LeafNode::nofKeys() const { return Psize(); } void LeafNode::printOn(ostream& out) const { out << " < "; for( int i = 0; i <= last; i++ ) out << *item[i] << " " ; out << "> "; } void LeafNode::pushLeft( int noFromThis, LeafNode* leftsib, int pidx ) { // noFromThis==1 => moves the parent item into the leftsib, // and the first item in this's array into the parent item PRECONDITION( noFromThis > 0 && noFromThis <= Psize() ); PRECONDITION( noFromThis + leftsib->Psize() < maxPsize() ); PRECONDITION( parent->getTree(pidx) == this ); leftsib->append( parent->getKey(pidx) ); if( noFromThis > 1 ) leftsib->appendFrom( this, 0, noFromThis-2 ); parent->setKey( pidx, item[noFromThis-1] ); shiftLeft( noFromThis ); parent->setNofKeys( pidx-1, leftsib->nofKeys() ); parent->setNofKeys( pidx, nofKeys() ); } void LeafNode::pushRight( int noFromThis, LeafNode* rightsib, int pidx ) { // noFromThis==1 => moves the parent item into the // rightsib, and the last item in this's array into the parent // item PRECONDITION(noFromThis > 0 && noFromThis <= Psize()); PRECONDITION(noFromThis + rightsib->Psize() < maxPsize()); PRECONDITION(parent->getTree(pidx) == rightsib); // The operation is five steps: // Step I. Make room for the incoming keys in RIGHTSIB. // Step II. Move the key in the parent into RIGHTSIB. // Step III.Move the items from THIS into RIGHTSIB. // Step IV. Move the item from THIS into the parent. // Step V. Update the length of THIS. // // Step I.: make space for noFromThis items // int start = last - noFromThis + 1; int tgt, src; tgt = rightsib->last + noFromThis; src = rightsib->last; rightsib->last = tgt; while (src >= 0) rightsib->item[tgt--] = rightsib->item[src--]; // Step II. Move the key from the parent into place rightsib->item[ tgt-- ] = parent->getKey( pidx ); // Step III.Move the items from THIS into RIGHTSIB for( int i = last; i > start; i-- ) rightsib->item[tgt--] = item[i]; CHECK( tgt == -1 ); // Step IV. parent->setKey( pidx, item[ start ] ); // Step V. last -= noFromThis; // Step VI. update nofKeys parent->setNofKeys( pidx-1, nofKeys() ); parent->setNofKeys( pidx, rightsib->nofKeys() ); } void LeafNode::remove( int index ) { PRECONDITION( index >= 0 && index <= last ); for( int to = index; to < last; to++ ) item[to] = item[to+1]; last--; if( parent == 0 ) tree->decrNofKeys(); else parent->decrNofKeys( this ); if( isLow() ) { if( parent == 0 ) { // then this is the root; when no keys left, inform the tree if( Psize() == 0 ) tree->rootIsEmpty(); } else parent->isLow( this ); } } void LeafNode::shiftLeft( int cnt ) { if( cnt <= 0 ) return; for( int i = cnt; i <= last; i++ ) item[i-cnt] = item[i]; last -= cnt; } void LeafNode::split() { // this function is called only when THIS is the only descendent // of the root node, and THIS needs to be split. // assumes that idx of THIS in Parent is 0. LeafNode* newnode = new LeafNode( parent ); CHECK( newnode != 0 ); parent->append( item[last--], newnode ); parent->setNofKeys( 0, parent->getTree(0)->nofKeys() ); parent->setNofKeys( 1, parent->getTree(1)->nofKeys() ); balanceWithRight( newnode, 1 ); } void LeafNode::splitWith( LeafNode *rightsib, int keyidx ) { PRECONDITION(parent == rightsib->parent); PRECONDITION(keyidx > 0 && keyidx <= parent->last); int nofKeys = Psize() + rightsib->Vsize(); int newSizeThis = nofKeys / 3; int newSizeNew = (nofKeys - newSizeThis) / 2; int newSizeSib = (nofKeys - newSizeThis - newSizeNew); int noFromThis = Psize() - newSizeThis; int noFromSib = rightsib->Vsize() - newSizeSib; CHECK(noFromThis >= 0); CHECK(noFromSib >= 1); LeafNode* newNode = new LeafNode(parent); CHECK( newNode != 0 ); parent->addElt( keyidx, item[last--], newNode ); parent->setNofKeys( keyidx, 0 ); parent->decNofKeys( keyidx-1 ); this->pushRight( noFromThis-1, newNode, keyidx ); rightsib->pushLeft( noFromSib, newNode, keyidx+1 ); if( parent->isFull() ) parent->informParent(); }