b树的c++实现

#include <iostream>
#include <vector>
#include <queue>

using namespace std;


class BTree{
	static const int M = 2;
	struct BTNode{
		int keyNum;
		int key[2 * M - 1];  //关键字数组
		struct BTNode* child[2 * M];//孩子结点数组
		bool isLeaf;
	};
	
	BTNode* root;
	//在插入时,保证pNode结点的关键字少于2*M-1个
	void InsertNonFull(BTNode* pNode, int key);
	//当child结点有2M-1个关键字时,分裂此结点
	void SplitChild(BTNode* parent, int i, BTNode* child);
	//两个M-1个元素的结点合并
	void merge(BTNode* parent, BTNode* pNode1, BTNode* pNode2, int index);
	//找到比pNode结点第一个关键字小的最大的关键字,也就是前继结点
	int predecessor(BTNode* pNode);
	//找到后继结点
	int successor(BTNode* pNode);
	//pNode1向parent要一个结点key[index],parent向pNode0要一个结点,pNode1关键字个数为M-1
	void ExchangeLeftNode(BTNode *parent, BTNode* pNode0, BTNode* pNode1, int index);
	void ExchangeRightNode(BTNode* parent, BTNode* pNode1, BTNode *pNode2, int index);
	//删除,结点关键字个数不少于M
	void RemoveNonLess(BTNode* pNode, int key);
	void DiskWrite(BTNode* pNode);
	void DiskRead(BTNode *pNode);
	BTNode* Search(BTNode* pNode, int key, int &index);
public:
	BTree();
	~BTree();
	BTNode* search(int key, int &index);
	void insert(int key);
	void remove(int key);
	//按层级打印。
	void PrintRow();
};

 
BTree::BTree()
{
	root = new BTNode();
	root->isLeaf = true;
	root->keyNum = 0;
	DiskWrite(root);
}

 
BTree::~BTree()
{
	struct BTNode* pNode;
	queue<struct BTNode*> q;
	q.push(root);
	while (!q.empty()){
		pNode = q.front();
		q.pop();
		
		if (pNode->isLeaf)
			continue;
		for (int i = 0; i <= pNode->keyNum; i++)
			q.push(pNode->child[i]);
		delete pNode;
	}
}

 
void BTree::DiskWrite(BTNode* pNode)
{

}

 
void BTree::DiskRead(BTNode *pNode)
{

}

 
BTree::BTNode* BTree::Search(BTNode* pNode, int key, int &index)
{
	int i = 0;
	while (i<pNode->keyNum&&key>pNode->key[i])//找到第一个大于等于key的下标
		i++;
	if (i < pNode->keyNum&&key == pNode->key[i]){//如果找到关键字,返回
		index = i;
		return pNode;
	}
	if (pNode->isLeaf)//已经搜到叶子结点,不存在
		return NULL;
	else{
		DiskRead(pNode->child[i]);
		return Search(pNode->child[i], key, index);//在第一个大于key值的孩子节点中递归搜索
	}
}

 
void BTree::InsertNonFull(BTNode* pNode, int key)
{
	int i = pNode->keyNum - 1;
	if (pNode->isLeaf){//如果是叶子结点,直接插入
		while (i >= 0 && key < pNode->key[i]){
			pNode->key[i + 1] = pNode->key[i];
			i--;
		}
		pNode->key[i + 1] = key;
		pNode->keyNum++;
		DiskWrite(pNode);
	}
	else {
		while (i >= 0 && key < pNode->key[i])
			i--;//找到第一个小于等于key的下标
		i++;
		DiskRead(pNode->child[i]);
		if (pNode->child[i]->keyNum == 2 * M - 1){//判断孩子结点是否有2*M-1个关键字,有就需要分裂
			SplitChild(pNode, i, pNode->child[i]);
			if (key>pNode->key[i])//如果key比上移到父节点的元素大
				i++;
		}
		InsertNonFull(pNode->child[i], key);//已保证孩子结点关键字个数少于2*M-1个
	}
}

 
void BTree::SplitChild(BTNode* parent, int i, BTNode* child)
{
	int j;
	struct BTNode* pNode = new BTNode();
	pNode->isLeaf = child->isLeaf;
	pNode->keyNum = M - 1;
	for (j = 0; j < M - 1; j++)//将child结点的后M-1个关键字赋给新节点
		pNode->key[j] = child->key[j + M];
	if (!child->isLeaf){//如果child不是叶子结点,将其后M个孩子结点赋给新节点。
		for (j = 0; j < M; j++)
			pNode->child[j] = child->child[j + M];
	}
	child->keyNum = M - 1;

	for (j = parent->keyNum; j > i; j--)
		parent->child[j + 1] = parent->child[j];//将child结点的父节点parent下标i以后的结点指针都向后移动一位,
	parent->child[j + 1] = pNode;//将新生成的结点当成parent的一个孩子
	for (j = parent->keyNum - 1; j >= i; j--)	//将i后面的关键字都向后移动一位
		parent->key[j + 1] = parent->key[j];
	parent->key[j + 1] = child->key[M - 1];//将孩子结点的中间结点移到父节点的指定位置
	parent->keyNum++;
	DiskWrite(parent);
	DiskWrite(pNode);
	DiskWrite(child);
}

 
void BTree::merge(BTNode* parent, BTNode* pNode1, BTNode* pNode2, int index)
{
	pNode1->key[M - 1] = parent->key[index];
	for (int i = 0; i < M - 1; i++)//将pNode2的关键字移到pNode1中
		pNode1->key[i + M] = pNode2->key[i];
	pNode1->keyNum = 2 * M - 1;
	if (!pNode1->isLeaf){//如果不是叶子,将pNode2的孩子指针也移到pNode1中
		for (int i = 0; i < M; i++)
			pNode1->child[i + M] = pNode2->child[i];
	}

	for (int i = index; i < parent->keyNum; i++){//将父节点index以后的关键字以及孩子指针都向前移动一位
		parent->key[i] = parent->key[i + 1];
		parent->child[i + 1] = parent->child[i + 2];
	}
	parent->keyNum--;
	delete pNode2;
}

 
int BTree::predecessor(BTNode* pNode)
{
	while (!pNode->isLeaf)
		pNode = pNode->child[pNode->keyNum];
	return pNode->key[pNode->keyNum - 1];
}

 int BTree::successor(BTNode* pNode)
{
	while (!pNode->isLeaf)
		pNode = pNode->child[0];
	return pNode->key[0];
}

 
void BTree::ExchangeLeftNode(BTNode *parent, BTNode* pNode0, BTNode* pNode1, int index)
{
	for (int i = pNode1->keyNum; i > 0; i--)
		pNode1->key[i] = pNode1->key[i - 1];//pNode1结点所有关键字向后移动一位
	pNode1->key[0] = parent->key[index];//第0个关键字来自父节点
	pNode1->keyNum++;
	parent->key[index] = pNode0->key[pNode0->keyNum - 1];//父节点的index处的关键字来自pNode0的最大关键字

	if (!pNode0->isLeaf){//如果不是叶子结点,
		for (int i = pNode1->keyNum; i > 0; i--)//将pNode1的孩子指针都向后移动一位,并将pNode0的最后一个孩子指针赋给它的第一个
			pNode1->child[i] = pNode1->child[i - 1];
		pNode1->child[0] = pNode0->child[pNode0->keyNum];
	}

	pNode0->keyNum--;
}

 
void BTree::ExchangeRightNode(BTNode* parent, BTNode* pNode1, BTNode *pNode2, int index)
{
	pNode1->key[pNode1->keyNum] = parent->key[index];
	pNode1->keyNum++;
	parent->key[index] = pNode2->key[0];
	for (int i = 0; i < pNode2->keyNum - 1; i++)
		pNode2->key[i] = pNode2->key[i + 1];

	if (!pNode2->isLeaf){
		pNode1->child[pNode1->keyNum] = pNode2->child[0];
		for (int i = 0; i < pNode2->keyNum; i++)
			pNode2->child[i] = pNode2->child[i + 1];
	}
	pNode2->keyNum--;
}

 
void BTree::RemoveNonLess(BTNode* pNode, int key)
{
	if (pNode->isLeaf){//到了叶子结点,直接删除
		int i = 0;
		while (i<pNode->keyNum&&key>pNode->key[i])
			i++;
		if (i < pNode->keyNum&&key == pNode->key[i]){
			while (i < pNode->keyNum - 1){
				pNode->key[i] = pNode->key[i + 1];
				i++;
			}
			pNode->keyNum--;
		}
		else {
			cout << "not found!" << endl;
		}
	}
	else {
		int i = 0;
		while (i < pNode->keyNum&&key > pNode->key[i])//找到第一个大于等于key的关键字
			i++;
		if (i < pNode->keyNum&&key == pNode->key[i]){//在结点中找到要删除的关键字
			struct BTNode* pNode1 = pNode->child[i];
			struct BTNode* pNode2 = pNode->child[i + 1];
			if (pNode1->keyNum >= M){//如果关键字左边的孩子结点的关键字数大于等于M
				int target = predecessor(pNode1);//将其前继结点移到pNode中
				pNode->key[i] = target;
				RemoveNonLess(pNode1, target);//递归删除target
			}
			else if (pNode2->keyNum >= M){//右边,同理
				int target = successor(pNode2);
				pNode->key[i] = target;
				RemoveNonLess(pNode2, target);
			}
			else {
				merge(pNode, pNode1, pNode2, i);//都小于M,合并
				RemoveNonLess(pNode1, key);
			}
		}
		else {//不在此结点中
			struct BTNode *pNode1 = pNode->child[i];
			struct BTNode *pNode0 = NULL;
			struct BTNode *pNode2 = NULL;
			if (i>0)
				pNode0 = pNode->child[i - 1];//左结点
			if (i < pNode->keyNum)
				pNode2 = pNode->child[i + 1];//右结点
			if (pNode1->keyNum == M - 1){//如果要删除的孩子结点关键字个数为M-1
				if (i > 0 && pNode0->keyNum >= M){//如果左邻结点至少有M个关键字,向其借一个
					ExchangeLeftNode(pNode, pNode0, pNode1, i - 1);
				}
				else if (i < pNode->keyNum&&pNode2->keyNum >= M){//同理,
					ExchangeRightNode(pNode, pNode1, pNode2, i);
				}
				else if (i>0){//两个相邻结点都只有M-1个关键字,合并
					merge(pNode, pNode0, pNode1, i - 1);
					pNode1 = pNode0;
				}
				else{
					merge(pNode, pNode1, pNode2, i);
				}
				RemoveNonLess(pNode1, key);

			}
			else{
				RemoveNonLess(pNode1, key);
			}
		}
	}
}

 
BTree::BTNode* BTree::search(int key, int &index)
{
	return Search(root, key, index);
}

 
void BTree::insert(int key)
{
	struct BTNode* r = root;
	if (root->keyNum == 2 * M - 1){//根节点特殊处理,如果根节点关键字个数为2*M-1,
		struct BTNode* pNode = new BTNode();//新建一个结点作为新的根节点,并将现在的根节点作为
		root = pNode;//新根节点的孩子结点
		pNode->isLeaf = false;
		pNode->keyNum = 0;
		pNode->child[0] = r;
		SplitChild(pNode, 0, r);//孩子结点r有2*M-1个关键字
		InsertNonFull(pNode, key);
	}
	else
		InsertNonFull(r, key);
}

 
void BTree::remove(int key)
{
	if (root->keyNum == 1){//如果根节点只有两个孩子
		struct BTNode* pNode1 = root->child[0];
		struct BTNode* pNode2 = root->child[1];
		if (pNode1->keyNum == M - 1 && pNode2->keyNum == M - 1){//且两个孩子都只有M-1个关键字,合并
			merge(root, pNode1, pNode2, 0);
			delete root;
			root = pNode1;
		}
		else {
			RemoveNonLess(root, key);
		}
	}
	else {
		RemoveNonLess(root, key);
	}
}

 
void BTree::PrintRow()
{
	struct BTNode* pNode;
	queue<struct BTNode*> q;
	q.push(root);
	while (!q.empty()){
		pNode = q.front();
		q.pop();
		cout << "[ ";
		for (int i = 0; i < pNode->keyNum; i++)
			cout << pNode->key[i] << " ";
		cout << "]" << endl;
		if (pNode->isLeaf)
			continue;
		for (int i = 0; i <= pNode->keyNum; i++)
			q.push(pNode->child[i]);
	}
}

int main(void)
{
	BTree tree;
	tree.insert('c');
	tree.insert('n');
	tree.insert('g');
	tree.insert('a');
	tree.insert('h');
	tree.insert('e');
	tree.insert('k');
	tree.insert('q');
	tree.insert('m');
	tree.insert('f');

	tree.insert('w');
	tree.insert('l');
	tree.insert('t');
	tree.insert('z');
	tree.insert('d');
	tree.insert('p');
	tree.insert('r');
	tree.insert('x');
	tree.insert('y');
	tree.insert('s');
	tree.remove('n');
	tree.remove('b');
	tree.PrintRow();

}


好吧,其实我只是把前面的c代码封装了一下,依旧是参考了《算法导论》以及http://blog.chinaunix.net/uid-20196318-id-3030529.html

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值