B树----B-TREE的实现

B树又叫平衡多路查找树,是一种组织和维护外存文件系统非常有效的数据结构
一棵m阶的B树(m叉树)的特性如下:
树中每个结点最多含有m个孩子(m>=2);
除根结点和叶子结点外,其它每个结点至少有[ceil(m / 2)]=(m-1)/2个孩子(其中ceil(x)是一个取上限的函数);
若根结点不是叶子结点,则至少有2个孩子(特殊情况:没有孩子的根结点,即根结点为叶子结点,整棵树只有一个根节点);
所有叶子结点都出现在同一层,叶子结点不包含任何关键字信息(可以看做是外部接点或查询失败的接点,
实际上这些结点不存在,指向这些结点的指针都为null);
每个非终端结点中包含有n个关键字信息: (n,P0,K1,P1,K2,P2,......,Kn,Pn)。其中:
a)   Ki (i=1...n)为关键字,且关键字按顺序升序排序K(i-1)< Ki。 
b)   Pi为指向子树根的接点,且指针P(i-1)指向子树种所有结点的关键字均小于Ki,但都大于K(i-1)。 
c)   关键字的个数n必须满足: (m-1)/2<= n <= m-1



* B树的插入算法
*将关键字K插入到B树中分两步进行:


(1)、利用前述的B树的查找算法找出该关键字的插入结点(插入结点一定是叶子结点)

(2)、判断该结点是否有空位置,即判断该结点是有满足n

直接插入即可(要保持该结点的关键字仍然有序);

若n=m-1,说明该结点已经没有空位置,要将该结点分裂成两个.分裂的做法是,取一个

新结点,把原结点上的关键字和k按升序排列,从中间位置((m+1)/2处)把关键字(

不包含中间关键字)分裂成两部分,左部分所含关键字放在旧节点中,右部分所含关键

字放在新结点中,中间关键字连同新结点的地址插入到父节点中。

如果父节点的关键字数也满了,那就向上继续分裂,最多是做到把根节点也分裂,产生

新的根节点。
*/

/*
*B树的删除算法
*要使得删除后的结点满足n>=(m-1)/2,将涉及到结点的"合并"问题。
*在B树中删除关键字K的过程分两步完成:

(1)、查找出该关键字所在结点

(2)、在结点上删除关键字k分两种情况:一是在叶子结点上删除、二在非叶子结点上删除

1)、在非叶子结点上删除关键字k的过程:假设要删除的关键字key[i],在删去该关键

字后,以该结点的ptr[i]所指向的子树中的最小关键字key[min]来代替被删关键

字key[i]所在的位置(注意ptr[i]所指子树中的最小关键字key[min]一定是在叶子

节点上),然后再也指针ptr[i]所指结点为根节点查找并删除key[min](即以ptr[i]

所指的结点为B树的根节点,key[min]为删除结点,然后调用B树的删除算法),这样

也就把在非叶子结点上删除关键字k的问题转化为在叶子结点上面删除关键字key[min]的问题。

2)、在叶子结点上删除关键字共分以下三种情况:

NO.1:如果被删除的结点的关键字数大于(m-1)/2,说明删去该关键字后,该结点仍满
足B树的定义,可以直接删除.

NO.2:如果被删除的结点的关键字数等于(m-1)/2,说明删去该节点后关键字数将不满足
B树的定义,此时若该结点的左(或右)兄弟结点的关键字树大于(m-1)/2,则把该
结点的左(或右)兄弟结点中最大(或最小)的关键字上移到双亲结点中,同时把双
亲结点中大于(或小于)上移关键字的关键字下移到要删除的关键字结点中,这样
删去该关键字后,该结点的以及它的左(或右)兄弟仍满足B树的定义.

NO.3:如果被删除的结点的关键字数等于(m-1)/2,并且该结点的左右兄弟(如果存在的话)的关键字数目
也都为(m-1)/2,这时,需要删除关键字的结点与其左(或右)兄弟结点以及双亲结点中分割二者的
关键字合并成一个新的结点。如果因此双亲结点中的关键字数小于(m-1)/2,则对双亲节点做同样
的处理,以至于可能对根结点做同样的处理以至于整棵树减少一层。


代码如下:

#include<iostream>
#include<queue>
using namespace std;
#define MAX_BTNODE 10
#define DEGREE 4

struct BTNode
{
	int keynum;															//当前存储关键字的个数
	char key[MAX_BTNODE];					    //当前存储节点的关键字,以非降序存放
	bool leaf;															//True为叶子,false为内节点
	BTNode *child[MAX_BTNODE];				    //指向子女的指针,比关键字多1个
	BTNode(int num,bool isleaf):keynum(num),leaf(isleaf){}	    //构造函数,初始化关键字数与是否为叶子标记
};

class B_Tree
{
public:
	B_Tree();
	void B_Tree_Init(char *key,int length);						//初始化空B-Tree,其中key是初始化时要记录的关键字
	void B_Tree_Insert(char key);							//向B-Tree中插入关键字
	void B_Tree_Insert_NonFull(BTNode *_root,char key);				//向B-Tree中插入关键字,用于辅助B_Tree_Insert函数
	void B_Tree_Split_Child(BTNode *_root,int i,BTNode *child);			//当B-Tree某节点已经超过了MAX_BTNODE,对B-Tree进行分裂,其中i为要插入到父节点的位置
	
	void B_Tree_Delete(char key);							//在B-Tree某节点删除key关键字
	bool B_Tree_Delete_NonLess(BTNode *_root,char key);				//在B-Tree某节点删除key关键字,用于辅助B_Tree_Delete函数
	void B_Tree_Move_From_Left(BTNode *_root,int location);				//在该节点,把key左边的前驱添加到key所在的树上
	void B_Tree_Move_From_Right(BTNode *_root,int location);			//在该节点,把key右边的后继添加到key所在的树上
	void B_Tree_Combine(BTNode *_root,int location);				//合并两个子树,两棵子树的keynum均为Degree - 1
	
	BTNode* B_Tree_Search(BTNode *_root,char key,int &location);		//在B-Tree中搜索关键字key,其中location为了记录所在节点中第几个位置
	bool B_Tree_Search_BTNode(BTNode *_root,char key,int &location);	//只在本节点进行搜索关键字key
	void B_Tree_Print_Order(BTNode *_root);					//按关键字大小进行输出
	void B_Tree_Print_Layer();						//对每层关键字进行输出
	void B_Tree_Print_BTNode(BTNode *_root);				//打印每个节点的关键字
	void B_Tree_QueuePush(BTNode *_root,queue<BTNode*> *btnqueue);		//对每个节点的孩子进行进栈
	BTNode* B_Tree_Root();
private:
	void B_Tree_Create();							//构建一棵空B-Tree
	BTNode *root;
};

B_Tree::B_Tree()
{
	B_Tree_Create();
}

void B_Tree::B_Tree_Create()
{
	root = new BTNode(0, true);
}

void B_Tree::B_Tree_Init(char *key,int length)
{
	int i = 0;
	while(i < length)
	{
		B_Tree_Insert(key[i]);
		i++;
	}
}

void B_Tree::B_Tree_Insert(char key)
{
	BTNode *r = root;
	if(r->keynum == 2 * DEGREE - 1)
	{
		BTNode *newroot = new BTNode(0,false);
		root = newroot;
		newroot->child[0] = r;
		B_Tree_Split_Child(newroot,0,r);		//判断根节点是否满了,其他内节点及叶节点满不满都交给B_Tree_Insert_NonFull			
		B_Tree_Insert_NonFull(newroot,key);
	}
	else
		B_Tree_Insert_NonFull(root,key);
}

void B_Tree::B_Tree_Insert_NonFull(BTNode *_root,char key)
{
	int i = _root->keynum - 1;

	if(_root->leaf)
	{
		while((i >= 0) && (key < _root->key[i]))
		{
			_root->key[i + 1] = _root->key[i];
			i--;
		}
		_root->key[i + 1] = key;
		_root->keynum++;
	}
	else
	{
		while((i >= 0) && (key < _root->key[i]))
			i--;
		i++;									//子孩子是从0开始
		if(_root->child[i]->keynum == 2 * DEGREE - 1)
		{
			B_Tree_Split_Child(_root,i,_root->child[i]);
			if(key > _root->key[i + 1])				//是孩子分裂过后才需要做这一步
				i++;
		}
		B_Tree_Insert_NonFull(_root->child[i],key);
	}
}

void B_Tree::B_Tree_Split_Child(BTNode *_root,int i,BTNode *child)
{
	BTNode *newNode = new BTNode(0,child->leaf);
	
	int j;
	for(j = 0; j < DEGREE - 1; j++)				//复制child后半段元素,共DEGREE - 1个,正好满孩子的时候,数组下标为2*DEGREE - 2
	{
		newNode->key[j] = child->key[j + DEGREE]; 
	}
	newNode->keynum = j;

	if(!newNode->leaf)
	{
		j--;									//下标从0开始
		for(j = 0; j <= DEGREE - 1; j++)		//注意这儿跟上面复制关键字的区别,要多复制一个,最后一个小标为2*DEGREE - 1
		{
			newNode->child[j] = child->child[j + DEGREE];
		}
	}

	child->keynum -= DEGREE;				//child的总数加上newNode的总数是2*Degree - 2,中间那个分裂到父节点i处

	for(j = _root->keynum - 1; j >= i; j--)		//_root有keynum个关键字,从keynum-1开始往前逐个往后移动
	{
		_root->key[j + 1] = _root->key[j];
	}
	_root->key[i] = child->key[child->keynum];
	
	for(j = _root->keynum; j > i; j--)			//_root有keynum+1个关键字,从keynum开始往前逐个往后移动
	{
		_root->child[j + 1] = _root->child[j];
	}
	_root->child[i + 1] = newNode;				//只需添加比新增节点的右孩子

	_root->keynum++;
}

BTNode* B_Tree::B_Tree_Search(BTNode *_root,char key,int &location)
{
	if(location < 1)
		location = 1;
	int i = 0;
	while((i <_root->keynum)&&(key > _root->key[i]))
		i++;
	if((i <_root->keynum)&&(key == _root->key[i]))
	{
		cout<<"we find "<<key<<" in layer "<<location<<" no. "<<(i + 1)<<endl;
		location = i;
		return _root;
	}
	if(_root->leaf)
		return NULL;
	else
		return B_Tree_Search(_root->child[i],key,++location);
}

bool B_Tree::B_Tree_Search_BTNode(BTNode *_root,char key,int &location)
{
	location = 0;
	while(location < _root->keynum && _root->key[location] < key)
		location++;

	if(location < _root->keynum && _root->key[location] == key)
		return true;
	else
		return false;
}

void B_Tree::B_Tree_Print_Layer()			//层次遍历
{
	int i,layer,layernodenum,nodekeynum;
	BTNode *temp;
	bool flag = false;
	queue<BTNode*> keyqueue;
	keyqueue.push(root);
	layer = 0;
	nodekeynum = 1;
	layernodenum = 0;
	//layernodenum = root->keynum + 1;		
	
	cout<<"this "<<layer<<" layer : ";
	while(!keyqueue.empty())
	{
		if(flag == true)
		{
			cout<<endl;
			cout<<"this "<<layer<<" layer : ";
			flag = false;
		}
		temp = keyqueue.front();
		keyqueue.pop();
		B_Tree_Print_BTNode(temp);
		B_Tree_QueuePush(temp,&keyqueue);
		nodekeynum--;
		layernodenum += temp->keynum + 1;
		if(nodekeynum == 0)
		{
			flag = true;
			nodekeynum = layernodenum;
			layer++;
			layernodenum = 0;
		}
	}
	cout<<endl;
}

void B_Tree::B_Tree_Print_BTNode(BTNode *_root)
{
	int i;
	for(i = 0; i < _root->keynum; i++)
	{
		cout<<_root->key[i]<<" ";
	}

	cout<<" ";
}

void B_Tree::B_Tree_QueuePush(BTNode *_root,queue<BTNode*> *btnqueue)
{
	if(!_root->leaf)
	{
		BTNode *temp;
		for(int i = 0;i <= _root->keynum; i++)
		{
			temp = _root->child[i];
			btnqueue->push(temp);
		}
	}
}

BTNode* B_Tree::B_Tree_Root()
{
	return this->root;
}

void B_Tree::B_Tree_Print_Order(BTNode *_root)
{
	if(_root->leaf)
		B_Tree_Print_BTNode(_root);
	else
	{
		int i;
		for(i = 0; i <= _root->keynum; i++)
		{
			B_Tree_Print_Order(_root->child[i]);
			if(i != _root->keynum)						//key的数量少于孩子的数量一个
				cout<<_root->key[i]<<"  ";
		}
	}
}

void B_Tree::B_Tree_Delete(char key)
{
	if(B_Tree_Delete_NonLess(root,key))
		cout<<"The key "<<key<<"is deleted!!!"<<endl;
	else
		cout<<"The key "<<key<<"is not exist in B_Tree!!!"<<endl;
}

bool B_Tree::B_Tree_Delete_NonLess(BTNode *_root,char key)
{
	bool deleteflag;
	if(_root == NULL)
		return false;
	else
	{
		int location = -1;
		if((deleteflag = B_Tree_Search_BTNode(_root,key,location)) == true)
		{
			if(!_root->leaf)							//当该节点是内节点
			{
				int childmaxnum = _root->child[location]->keynum;
				_root->key[location] = _root->child[location]->key[childmaxnum - 1];	//找到左边节点最大的关键字进行替换
				B_Tree_Delete_NonLess(_root->child[location],_root->key[location]);
			}
			else
			{
				int i;
				for(i = location + 1; i < _root->keynum; i++)							//删除叶节点的关键字
				{
					_root->key[i - 1] = _root->key[i];
				}
				_root->keynum--;
			}
		}
		else
			deleteflag = B_Tree_Delete_NonLess(_root->child[location],key);				//如果在当前节点没找到,继续按照查找路径往下查找
		if(!_root->leaf)																//依次往上检查是否出现子节点的关键字不够的情况
		{
			if(_root->child[location]->keynum < DEGREE - 1)								//分别分析在最左边跟最右边及其在其他的位置的情况
			{
				if(location == 0)										
				{
					if(_root->child[location + 1]->keynum > DEGREE - 1)
						B_Tree_Move_From_Right(_root,location);
					else
						B_Tree_Combine(_root,location);
				}
				else if(location == _root->keynum - 1)
				{
					if(_root->child[location - 1]->keynum > DEGREE - 1)
						B_Tree_Move_From_Left(_root,location);
					else
						B_Tree_Combine(_root,location);
				}
				else
				{
					if(_root->child[location - 1]->keynum > DEGREE - 1)
						B_Tree_Move_From_Left(_root,location);
					else if(_root->child[location + 1]->keynum > DEGREE - 1)
						B_Tree_Move_From_Right(_root,location);
					else
						B_Tree_Combine(_root,location);
				}
			}
		}
		return deleteflag;
	}
}

void B_Tree::B_Tree_Move_From_Left(BTNode *_root,int location)
{
	int i;
	BTNode *temp = _root->child[location];
	temp->child[temp->keynum + 1] = temp->child[temp->keynum];
	for(i = temp->keynum; i > 0; i--)
	{
		temp->key[i] = temp->key[i - 1];
		temp->child[i] = temp->child[i - 1];
	}
	temp->key[i] = _root->key[location - 1];
	temp->keynum++;

	temp = _root->child[location - 1];
	_root->key[location - 1] = temp->key[temp->keynum - 1];
	_root->child[location]->child[i] = temp->child[temp->keynum];
	temp->keynum--;
}

void B_Tree::B_Tree_Move_From_Right(BTNode *_root,int location)
{
	BTNode *temp = _root->child[location];
	temp->key[temp->keynum] = _root->key[location];
	temp->child[temp->keynum + 1] = _root->child[location + 1]->child[0];
	temp->keynum++;

	temp = _root->child[location + 1];
	_root->key[location] = temp->key[0];
	int i;
	for(i = 1; i < temp->keynum; i++)
	{
		temp->key[i - 1] = temp->key[i];
		temp->child[i - 1] = temp->child[i];
	}
	temp->child[i - 1] = temp->child[i];
}

void B_Tree::B_Tree_Combine(BTNode *_root,int location)
{
	BTNode *templeft = _root->child[location];
	BTNode *tempright = _root->child[location + 1];

	int i,j;
	templeft->key[templeft->keynum] = _root->key[location];
	templeft->keynum++;
	j = templeft->keynum;
	for(i = 0; i < tempright->keynum;i++)
	{
		templeft->key[j] = tempright->key[i];
		templeft->child[j] = tempright->child[i];
		j++;
	}
	templeft->child[j] = tempright->child[i];
	templeft->keynum = j;
	_root->child[location + 1] = templeft;
	for(i = location + 1; i < _root->keynum;i++)
	{
		_root->key[i - 1] = _root->key[i];
		_root->child[i - 1] = _root->child[i];
	}
	_root->child[i - 1] = _root->child[i];
	_root->keynum--;
	delete tempright;
}

int main()
{
	B_Tree *tree = new B_Tree();
	int location;
	char key[] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
		'a','b','c','d','e','f','g','h',',i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
	tree->B_Tree_Init(key,52);
	tree->B_Tree_Print_Layer();
	tree->B_Tree_Search(tree->B_Tree_Root(),'j',location);
	tree->B_Tree_Print_Order(tree->B_Tree_Root());
	tree->B_Tree_Delete('B');
	tree->B_Tree_Print_Layer();
	return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值