⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bptree.cpp

📁 用c语言实现的一个小型dbms
💻 CPP
📖 第 1 页 / 共 3 页
字号:

///////////////////////////////////////////////////////////////////////////////////////////////////
//this method returns the address specified by Key_Location
//--
_F_FileAddr BPTree::getCurRecAddr(Key_Location KeyLoca) {
	BPTreeNode node;
	node.readNodeFromFile(KeyLoca.ptr);
	return node.p[KeyLoca.offset];
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//--
_F_FileAddr BPTree::createNodeInFile() {
	BPTree_Index idx;
	idx.readHeadFromFile();
	//the index file has no empty block
	if( 0 == idx.IdxHead.FirstEmptyBlock.ulFilePageID ) {
		// firstly,we should check whether the block overflow the current page
		// If so,use the next page 
		void* CheckOverflow = (void*) new char[BTreeNodeSize];
		_F_FileAddr Next = MemWrite(CheckOverflow, BTreeNodeSize, &idx.IdxHead.FirstNewBlock);
		_F_FileAddr temp = idx.IdxHead.FirstNewBlock;
		idx.IdxHead.FirstNewBlock = Next;
		idx.writeHeadToFile();
		return temp;
	}
	else {
		int flag = 0;  
		if(idx.IdxHead.FirstEmptyBlock ==  idx.IdxHead.LastEmptyBlock)
			flag = 1;
		_F_FileAddr temp = idx.IdxHead.FirstEmptyBlock;
		if( 1 == flag) { 
			//there is just one empty block
			idx.IdxHead.FirstEmptyBlock.ulFilePageID = 0;
			idx.IdxHead.FirstEmptyBlock.uiOffset     = 0;
			idx.IdxHead.LastEmptyBlock.ulFilePageID  = 0;
			idx.IdxHead.LastEmptyBlock.uiOffset      = 0;
		}
		else {
			// change FisrtEmptyBlock point to the next block
			BPTreeNode NextNode;
			NextNode.readNodeFromFile(temp);
			idx.IdxHead.FirstEmptyBlock = NextNode.Next_Empty_Block;
		}
		idx.writeHeadToFile();
		return temp;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//this method returns the address of the last key in the rightest node
//--
Key_Location BPTree::getEnd() {
	BPTree_Index idx;
	idx.readHeadFromFile();
	_F_FileAddr ptr = idx.getRoot();

	for( ; ; ) {
		BPTreeNode Node;
		Node.readNodeFromFile(ptr);
		if( 1 == Node.IsLeaf ) {
			Key_Location temp;
			temp.ptr = ptr;
			temp.offset = Node.ItemOnNode - 1;
			return temp;  // return the first address of the first Key in the first node
		}
		else
			ptr = Node.p[Node.ItemOnNode];
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//--
void BPTree::insert(pKey_Attr pPrimKey, _F_FileAddr pRec) {
	setPath();
	Key_Location KeyLoca;
	if(search(pPrimKey, &KeyLoca))
		throw 1024;
	else 
		insert_entry(KeyLoca.ptr, pPrimKey, pRec);
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//--
void BPTree::insert_entry(_F_FileAddr L, pKey_Attr pPrimKey, _F_FileAddr pRec) {
	BPTreeNode NodeL;
	NodeL.readNodeFromFile(L);
	//if L has less than n-1 key values
	if(NodeL.ItemOnNode < NodeL.MaxItem) {
		if(NodeL.IsLeaf ==1)
			NodeL.insertKeyInLeaf(pRec, pPrimKey);
		else
			NodeL.insertKeyNotLeaf(pPrimKey, pRec);
	}
	else {
		//create a new node
		_F_FileAddr L_ = createNodeInFile();
		BPTreeNode NodeL_;
		pKey_Attr pPrimKey_;
		int n = NodeL.MaxItem + 1;

		if(NodeL.IsLeaf ==1) {
			NodeL_.IsLeaf = 1;
			int m;
			if( !(n%2) )
				m = n/2 ;
			else 
				m = n/2 + 1;
			//p[0]k[0]...k[m-1]p[m] | k[m]...
			// pPrimKey < k[m-1]
			if( NodeL.compare(NodeL.k[m-1], pPrimKey) > 0) { 
				m--;                                  
				pPrimKey_ = NodeL.createKey(NodeL.k[m]);
			}
			// k[m] > pPrimKey >= k[m-1]
			else if( (m == n - 1) || ( NodeL.compare(NodeL.k[m], pPrimKey) > 0 ) ) 
				pPrimKey_ = NodeL.createKey(pPrimKey);
			else
				// pPrimKey > k[m]
				pPrimKey_ = NodeL.createKey(NodeL.k[m]);
			//copy p[m]....to L_
			for(int i=m; i<NodeL.MaxItem; i++) {
				NodeL_.p[i-m] = NodeL.p[i];
				NodeL_.k[i-m] = NodeL.k[i];
				//erase
				NodeL.k[i] = NULL;
				NodeL.p[i].ulFilePageID = 0;
				NodeL.p[i].uiOffset     = 0;
				NodeL_.ItemOnNode++;
				NodeL.ItemOnNode--;
			}
			if(NodeL.compare(pPrimKey, pPrimKey_) < 0)
				NodeL.insertKeyInLeaf(pRec,pPrimKey);
			else
				NodeL_.insertKeyInLeaf(pRec,pPrimKey);
		}
		else { //NodeL is not a leaf
			NodeL_.IsLeaf = 0;
			int m;
			if( !(n%2) )
				m = n/2 ;
			else 
				m = n/2 + 1;
			m = NodeL.MaxItem - m;
			//p[0],k[0]....k[m]p[m+1] | k[m+1]...
			//pPrimKey > k[m+1]
			if( NodeL.compare(pPrimKey, NodeL.k[m+1]) > 0 ) {
				m++;
				pPrimKey_ = NodeL.createKey(NodeL.k[m]);
			}
			// k[m] < pPrimKey <= k[m+1]
			else if( NodeL.compare(pPrimKey, NodeL.k[m]) > 0 ) {
				m++;
				pPrimKey_ = NodeL.createKey(pPrimKey);
			}
			// pPrimKey <= k[m]
			else {
				pPrimKey_ = NodeL.createKey(NodeL.k[m]);
			}
			// move and delete
			NodeL_.p[0].ulFilePageID = 0;
			NodeL_.p[0].uiOffset     = 0;  
			NodeL_.k[0] = NodeL.k[m];
			NodeL.k[m] = NULL;
			NodeL_.ItemOnNode++;
			NodeL.ItemOnNode--;
			for(int i=m+1; i<NodeL.MaxItem; i++) {
				NodeL_.p[i-m] = NodeL.p[i];
				NodeL_.k[i-m] = NodeL.k[i];
				//erase
				NodeL.k[i] = NULL;
				NodeL.p[i].ulFilePageID = 0;
				NodeL.p[i].uiOffset     = 0;
				NodeL_.ItemOnNode++;
				NodeL.ItemOnNode--;
			}
			NodeL_.p[i-m] = NodeL.p[i];
			NodeL.p[i].ulFilePageID = 0;
			NodeL.p[i].uiOffset     = 0;
			if( NodeL.compare(pPrimKey, pPrimKey_) < 0 )
				NodeL.insertKeyNotLeaf(pPrimKey, pRec);
			else 
				NodeL_.insertKeyNotLeaf(pPrimKey,pRec);
			NodeL_.deleteFirstKey();
		}
		if( !isRoot(L) )
			insert_entry(getParent(L), pPrimKey_, L_);
		else
			createNewRoot(L, pPrimKey_, L_);  
		if(NodeL.IsLeaf == 1) {
			NodeL_.p[NodeL.MaxItem] = NodeL.p[NodeL.MaxItem];
			NodeL.p[NodeL.MaxItem]  = L_;
		}
		NodeL_.writeNodeToFile(L_);
	}
	NodeL.writeNodeToFile(L);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////

bool BPTree::canCoalesce(BPTreeNode* pNode, BPTreeNode* pNode_) {
	if(pNode->IsLeaf == 1)
		return (pNode->ItemOnNode + pNode_->ItemOnNode <= pNode->MaxItem);
	else
		return (pNode->ItemOnNode + pNode_->ItemOnNode < pNode->MaxItem);   
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////


void BPTree::coalesce(BPTreeNode* pNodeL, BPTreeNode* pNodeL_, pKey_Attr pPrimKey_, bool IsLLeftOfL_) {
	if( 0 == pNodeL->IsLeaf ) {
		if(IsLLeftOfL_) {
			//move right
			int j = pNodeL->ItemOnNode + 1;
			pNodeL_->p[pNodeL_->ItemOnNode + j] = pNodeL_->p[pNodeL_->ItemOnNode];
			for(int i=pNodeL_->ItemOnNode-1; i>=0; i--) {
				pNodeL_->k[i + j] = pNodeL_->k[i];
				pNodeL_->p[i + j] = pNodeL_->p[i];
			}
			//assign V' to the pNodeL_
			pNodeL_->k[j-1] = pPrimKey_;
			pNodeL_->p[j-1] = pNodeL->p[pNodeL->ItemOnNode];
			// move all elements in pNodeL to pNodeL_
			for(i=0; i<pNodeL->ItemOnNode; i++) {
				pNodeL_->p[i] = pNodeL->p[i];
				pNodeL_->k[i] = pNodeL->k[i];
			}
			// set ItemOnNode in pNodeL_
			pNodeL_->ItemOnNode = pNodeL_->ItemOnNode + pNodeL->ItemOnNode + 1;
			pNodeL->initialize();
		}
		else { //L is right of L_
			int j = pNodeL_->ItemOnNode + 1;
			pNodeL_->k[pNodeL_->ItemOnNode] = pPrimKey_; 
			for(int i=0;i<pNodeL->ItemOnNode;i++) {
				pNodeL_->p[i+j] = pNodeL->p[i];
				pNodeL_->k[i+j] = pNodeL->k[i];
			}
			pNodeL_->p[i+j] = pNodeL->p[i];
			pNodeL_->ItemOnNode = pNodeL_->ItemOnNode + pNodeL->ItemOnNode + 1;
			pNodeL->initialize();
		}
	}
	else { // (pNodeL->IsLeaf == 1)
		if(IsLLeftOfL_) {
			int j = pNodeL->ItemOnNode;
			for(int i=0; i<pNodeL_->ItemOnNode; i++) {
				pNodeL->p[i+j] = pNodeL_->p[i];
				pNodeL->k[i+j] = pNodeL_->k[i];
			}
			pNodeL->ItemOnNode += pNodeL_->ItemOnNode;
			pNodeL->p[pNodeL->MaxItem] = pNodeL_->p[pNodeL_->MaxItem];
			pNodeL_->initialize();
		}
		else { // L is right of L_
			int j = pNodeL_->ItemOnNode;
			for(int i=0; i<pNodeL->ItemOnNode; i++) {
				pNodeL_->p[i+j] = pNodeL->p[i];
				pNodeL_->k[i+j] = pNodeL->k[i];
			}
			pNodeL_->ItemOnNode += pNodeL->ItemOnNode;
			pNodeL_->p[pNodeL_->MaxItem] = pNodeL->p[pNodeL->MaxItem];
			pNodeL->initialize();
		}
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
//this method swaps the pointers to node L and L_

void BPTree::swapVariables(_F_FileAddr L, _F_FileAddr L_) {
	BPTreeNode ParentNode;
	ParentNode.readNodeFromFile(getParent(L));
	int m,n;
	// find the indexes of L and L_ 
	for(int i=0; i <= ParentNode.ItemOnNode; i++) {
		if( ParentNode.p[i] == L )
			m = i;
		if( ParentNode.p[i] == L_ )
			n = i;
	}
	// swap
	_F_FileAddr temp;
	temp = ParentNode.p[m];
	ParentNode.p[m] = ParentNode.p[n];
	ParentNode.p[n] = temp;
	ParentNode.writeNodeToFile(getParent(L));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
//this method makes pL_ and ppPrimKey points the infomation that is a neighbour of L
// and pIsLLeftOnL_ indicate whether L is left neighbour of L_ or not

void BPTree::setNb(_F_FileAddr L, _F_FileAddr* pL_, pKey_Attr* ppPrimKey_, bool* pIsLLeftOfL_) {
	BPTreeNode ParentNode;
	ParentNode.readNodeFromFile(getParent(L));
	for(int i=0; i<=ParentNode.ItemOnNode; i++) {
		if( ParentNode.p[i] == L )
			break;
	}
	if( 0 == i ) { // L is the leftest son of the parent node
		(*pL_)          = ParentNode.p[1];
		(*ppPrimKey_)   = ParentNode.createKey(ParentNode.k[0]);
		(*pIsLLeftOfL_) = true;  // L is on the left of L_
	}
	else {
		(*pL_)          = ParentNode.p[i-1];
		(*ppPrimKey_)   = ParentNode.createKey(ParentNode.k[i-1]);
		(*pIsLLeftOfL_) = false;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
//this method replaces the key equal to Key_ with Key in the node pointed by ptr  
//--
void BPTree::replaceKey(_F_FileAddr ptr, pKey_Attr Key_, pKey_Attr Key) {
	BPTreeNode Node;
	Node.readNodeFromFile(ptr);
	for(int i=0; i<Node.ItemOnNode; i++) {
		if( 0 == Node.compare(Node.k[i], Key_) )
			break;
	}
	Node.deleteKeySpace(Node.k[i]);
	Node.k[i] = Key;
	Node.writeNodeToFile(ptr);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////

void BPTree::reDistribute(BPTreeNode* pNodeL, BPTreeNode* pNodeL_, pKey_Attr pPrimKey_, 
						  bool IsLLeftOfL_, _F_FileAddr L) {
	int m;
	if( !IsLLeftOfL_ ) {
		if( !pNodeL->IsLeaf ) {
			m = pNodeL_->ItemOnNode;
			//  move all k[i] and p[i] in L to right by one
			pNodeL->p[pNodeL->ItemOnNode+1] = pNodeL->p[pNodeL->ItemOnNode];
			for(int i=pNodeL->ItemOnNode-1; i>=0; i--) {
				pNodeL->k[i+1] = pNodeL->k[i];
				pNodeL->p[i+1] = pNodeL->p[i];
			}
			pNodeL->k[0] = pPrimKey_;
			pNodeL->p[0] = pNodeL_->p[m];
			pNodeL->ItemOnNode++;
			//replace K_ in parent of L by k[m-1]
			replaceKey(getParent(L), pPrimKey_, pNodeL_->k[m-1]);
			//remove k[m-1] and p[m] from L_
			pNodeL_->k[m-1] = NULL;
			pNodeL_->p[m].ulFilePageID = 0;
			pNodeL_->p[m].uiOffset     = 0;
			pNodeL_->ItemOnNode--;
		}
		else { //(pNodeL->IsLeaf == 1)
			m = pNodeL_->ItemOnNode - 1;
			//  move all k[i] and p[i] in L to right by one
			for(int i=pNodeL->ItemOnNode-1; i>=0; i--) {
				pNodeL->k[i+1] = pNodeL->k[i];
				pNodeL->p[i+1] = pNodeL->p[i];
			}
			pNodeL->k[0] = pNodeL_->k[m];
			pNodeL->p[0] = pNodeL_->p[m];
			pNodeL->ItemOnNode++;
			//replace K_ in parent of L by k[m]
			pKey_Attr temp = pNodeL_->createKey(pNodeL_->k[m]);
			replaceKey(getParent(L), pPrimKey_, temp);
			pNodeL->deleteKeySpace(pPrimKey_);
			//remove p[m] and k[m] from L_ 
			pNodeL_->k[m] = NULL;
			pNodeL_->p[m].ulFilePageID = 0;
			pNodeL_->p[m].uiOffset     = 0;
			pNodeL_->ItemOnNode--;
		}
	}
	else { //(IsLLeftOfL_)
		if( !pNodeL->IsLeaf ) {
			pNodeL->k[pNodeL->ItemOnNode] = pPrimKey_;
			pNodeL->p[pNodeL->ItemOnNode + 1] = pNodeL_->p[0];
			pNodeL->ItemOnNode++;
			replaceKey(getParent(L), pPrimKey_, pNodeL_->k[0]);
			// move pNodeL_ to the left by one
			for(int i=1; i<pNodeL_->ItemOnNode; i++) {
				pNodeL_->k[i-1] = pNodeL_->k[i];
				pNodeL_->p[i-1] = pNodeL_->p[i];
			}
			pNodeL_->p[i-1] = pNodeL_->p[i];

			pNodeL_->k[pNodeL_->ItemOnNode-1] = NULL;
			pNodeL_->p[pNodeL_->ItemOnNode].ulFilePageID = 0;
			pNodeL_->p[pNodeL_->ItemOnNode].uiOffset     = 0;
			pNodeL_->ItemOnNode--;
		}
		else { //(pNodeL->IsLeaf)
			pNodeL->k[pNodeL->ItemOnNode] = pNodeL_->k[0];
			pNodeL->p[pNodeL->ItemOnNode] = pNodeL_->p[0];
			pNodeL->ItemOnNode++;
			for(int i=1; i<pNodeL_->ItemOnNode; i++) {
				pNodeL_->k[i-1] = pNodeL_->k[i];
				pNodeL_->p[i-1] = pNodeL_->p[i];
			}
			pNodeL_->k[pNodeL_->ItemOnNode-1] = NULL;
			pNodeL_->p[pNodeL_->ItemOnNode-1].ulFilePageID = 0;
			pNodeL_->p[pNodeL_->ItemOnNode-1].uiOffset     = 0;
			pNodeL_->ItemOnNode--;
			pKey_Attr temp = pNodeL_->createKey(pNodeL_->k[0]); 
			replaceKey(getParent(L), pPrimKey_, temp);
			pNodeL->deleteKeySpace(pPrimKey_);
		}
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////

void BPTree::myDelete(pKey_Attr pPrimKey, _F_FileAddr& pRec) {
	setPath();
	Key_Location KeyLoca;
	if(search(pPrimKey, &KeyLoca)) {
		pRec = getCurRecAddr(KeyLoca);
		delete_entry(KeyLoca.ptr, pPrimKey, pRec);    
	}
	else
		throw 1023;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////

void BPTree::delete_entry(_F_FileAddr L, pKey_Attr pPrimKey, _F_FileAddr pRec) {
	BPTreeNode NodeL;
	NodeL.readNodeFromFile(L);
	// delete the (V,P) entry
	if( 1 == NodeL.IsLeaf )
		NodeL.deleteKeyInLeaf(pPrimKey);
	else 
		NodeL.deleteKeyNotLeaf(pPrimKey);
	// L is root and has only one son and not a leaf
	if( isRoot(L) && ( 0 == NodeL.ItemOnNode ) && (0 == NodeL.IsLeaf) )  {
		grantRoot(NodeL.p[0]); // grant root to the son
		deleteNodeInFile(L);   // delete node 
	}
	else 
		if( !isRoot(L) && NodeL.isNotEnoughPoints() )  {// isn't root and not enough points
			//set L_ neighbour of L
			bool IsLLeftOfL_;
			_F_FileAddr L_;
			pKey_Attr pPrimKey_;
			setNb(L, &L_, &pPrimKey_, &IsLLeftOfL_);
    
			BPTreeNode NodeL_;
			NodeL_.readNodeFromFile(L_);
			if( canCoalesce(&NodeL, &NodeL_)) {
				if(IsLLeftOfL_) 
					swapVariables(L,L_); 
				coalesce(&NodeL, &NodeL_, pPrimKey_, IsLLeftOfL_);
				if( NodeL.IsLeaf && IsLLeftOfL_ ) // differe from book 
					swapVariables(L,L_);       

				delete_entry(getParent(L), pPrimKey_, L);
				if( NodeL.IsLeaf && IsLLeftOfL_ )  // L is a leaf and L < L_. Different from the book
					deleteNodeInFile(L_);  // delete the node pointed by L_
				else
					deleteNodeInFile(L);   // delete the node pointed by L
			}
			else 
			  reDistribute(&NodeL, &NodeL_, pPrimKey_, IsLLeftOfL_, L);

			NodeL_.writeNodeToFile(L_);
		}
		NodeL.writeNodeToFile(L);  // if though the node is delete
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -