`
hao3100590
  • 浏览: 131805 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

B-树实现

 
阅读更多

1.什么是B-树?

这个在我的前一篇博客中已经详细的阐释过:

http://hao3100590.iteye.com/blog/1576846

具体的了解,好好看看这篇文章就可以了!

 

2.实现关键问题分析

a.B-树删除原则

见下图:


 当然总结起来,大的方面就3点,具体的细节就没有做多大的说明,在下面具体实现的时候会说明

 

b.B-树的递归和非递归遍历

对于非递归遍历,比较麻烦,自己需要按照下面图中所示的方式来遍历B-树,输出的关键字大小从小到大排列,但是对于递归却相当简单,这里非递归没有利用栈来实现,所以注意!



 c.B-树删除伪代码

见下图:


d.具体删除之借详细演示

如下图:

3.关键函数说明

void insertList(T a[], int n, T x, int *p);

void deleteList(T *a, int n, int p);

void insertPoint(Node<T> *a[], int n, Node<T>* p, int pos);

void deletePoint(Node<T> *a[], int n, int p);

上面四个函数是实现插入和删除在Node中的关键字数组和指针数组的插入删除操作(就是数组删除)

 

下面的函数主要就是对插入和删除的操作

//插入的时候分裂提升结点p

Node<T>* divideTree(Node<T>* &root, Node<T>* &p);

//修改结点p的所有孩子结点的父节点为p,因为当删除的时候,父亲节点也可能改变

void modifyParent(Node<T>* &p);

//查询结点p在结点parent中的位置,或者关键字在结点parent中的位置(寻找插入位置或者查找)

int position(Node<T>* parent, Node<T>* p, T key);

//parent为p的双亲,从兄弟借元素(如果兄弟可借,否则什么都不做),pos是p中待删除元素的位置

 bool borrowFromSib(Node<T>* &parent, Node<T>* p, int pos);

//从parent的儿子中借一个然后删除parent中一个关键字(pos是parent待删除位置)

bool borrowFromSon(Node<T>* &parent, int pos);

//合并在parent中位置在pos处关键字的左右儿子,如果key[pos]是待删除的则设置flag=true

void mergeSib(Node<T>* &parent, int pos, bool flag);

//删除的时候递归合并操作

void recursionMerge(Node<T>* &p);

//合并结点q到p中(当删除的时候用)

void merge2Node(Node<T>* &p, Node<T>* q);

 

4。代码实现

a.btree.h

 

//B树(B-树)的头文件定义
#ifndef BTREE_H
#define BTREE_H
const int M=20;

template<class T>
struct Node{
	int keyNum;			//the number of key
	T key[M];        //the array of key
	Node<T>* parent;//point to parent
	Node<T>* son[M];//point to sons
	//construct function! very important!!!!!!!!!!!
	Node(){
		parent = 0;
		for(int i=0; i<M; i++){
			key[i] = 0;
			son[i] = 0;
		}
	}
};

template<class T>
class BTree{
  public:
  	BTree(int m);
  	//m:B-树的阶,长度为n的数组a
  	BTree(int m, T a[], int n);
  	~BTree();
  	Node<T>* insertBT(T x);
  	//void insertBT(Node<T>* &root, T x, int pos);//递归还没做出来
  	Node<T>* deleteBT(T x);
  	//x是查询关键字;pos是x在结点中的位置;p为k所在结点的双亲结点,如果没找到,也返回失败的叶子结点
  	Node<T>* search(T x, int *pos, Node<T>* &p);
  	int height();
  	void printBT();						 		//非递归打印
  	void printBT(Node<T>* root);  //递归打印
  	Node<T>* getRoot();
  private:
  	int m;						//m阶B-树
  	Node<T>* root;
  	void create(Node<T>* &root);
  	void release(Node<T>* &root);
  	void insertList(T a[], int n, T x, int *p); 									//将x插入有序数组a(递增),p为插入位置
  	void insertPoint(Node<T> *a[], int n, Node<T>* p, int pos);		//将节点指针p插入指针数组a的位置pos
  	void deleteList(T *a, int n, int p);													//删除数组中位置是p的数据
  	void deletePoint(Node<T> *a[], int n, int p);									//删除数组中位置是p的结点
  	Node<T>* divideTree(Node<T>* &root, Node<T>* &p);							//分裂提升结点p
  	void modifyParent(Node<T>* &p);																//修改结点p的所有孩子结点的父节点为p
  	//删除需要用的函数
  	int position(Node<T>* parent, Node<T>* p, T key);							//查询结点p在结点parent中的位置,或者关键字在结点parent中的位置
  	bool borrowFromSib(Node<T>* &parent, Node<T>* p, int pos);		//parent为p的双亲,从兄弟借元素(如果兄弟可借,否则什么都不做),pos是p中待删除元素的位置
		bool borrowFromSon(Node<T>* &parent, int pos);								//从parent的儿子中借一个然后删除parent中一个关键字(pos是parent待删除位置)
		void mergeSib(Node<T>* &parent, int pos, bool flag);					//合并在parent中位置在pos处关键字的左右儿子,如果key[pos]是待删除的则设置flag=true
		void recursionMerge(Node<T>* &p);															//递归合并
		void merge2Node(Node<T>* &p, Node<T>* q);											//合并结点q到p中
};
#endif

 

 b.btree.cpp

 

#include <iostream>
#include "btree.h"
using namespace std;

template<class T>
BTree<T>::BTree(int m){
	this->m = m;
	root = NULL;
	create(root);
}

template<class T>
BTree<T>::BTree(int m, T a[], int n){
	this->m = m;
	root = NULL;
	if(n<=0) return;
	for(int i=0; i<n; i++){
		insertBT(a[i]);
	}
}

template<class T>
BTree<T>::~BTree(){
	release(root);
}

template<class T>
Node<T>* BTree<T>::getRoot(){
	return root;
}

/**
	*插入的原则是分裂-提升
	*对于m阶子树的:根(非叶子)关键字个数是 1~m-1;非根关键字个数 m/2的上界-1~m-1
	*一旦超过这个范围就执行分裂
	*/
template<class T>
Node<T>* BTree<T>::insertBT(T x){
	Node<T>* r = root;
	Node<T>* p = NULL;
	int pos = 0;			//待插入位置
	if(!root){
		root = new Node<T>;
		root->keyNum = 1;
		root->parent = NULL;
		//注:结构体key和son都会自己初始化为空
		(root->key)[0] = x;
	}else{
		//如果树中还没有x,就插入;否则,什么都不做,返回
		r = search(x, &pos, p);
		if(!r){
			insertList(p->key, p->keyNum, x, &pos);
			p->keyNum++;
		}else{
			return root;
		}
		
		//查看刚才插入的结点p是否达到上界,如果达到关键字上界,就分裂-提升
		//分裂-提升:将中间的key拿出来,提升到父结点,然后两边的key分成两个单独的结点,直到root结点
		if(p->keyNum >= m){
			cout<<"分裂-提升"<<endl;
			Node<T>* parent = divideTree(root, p);
			while(parent && parent->keyNum >= m){				
				cout<<"继续提升!"<<endl;
				parent = divideTree(root, parent);
			}
		}
	}
	return root;
}

//删除,就依据两个原则:借和下降-合并(注:一下降就可能造成其父节点不足,需递归向上)
template<class T>
Node<T>* BTree<T>::deleteBT(T x){
	Node<T>* r = root;
	Node<T>* p = NULL;
	int pos = 0;												//待插入位置
	int t = 0;
	if(!r) return NULL;
	else{
		r = search(x, &pos, p);
		if(!r) return NULL;								//搜索x,如果没找到,返回空
		else{
			int low = m%2==0 ? m/2-1 : m/2; 
			//1.************************如果待删除的结点是叶子结点************************
			if(!r->son[0]){
				//1.1.--------如果该结点充足,则直接删除结点--------------------
				if(r->keyNum > low){
					 deleteList(r->key, r->keyNum, pos);
					 r->keyNum--;
				}
				//1.2.--------如果该结点不足,兄弟可借(向左或者右兄弟借)--------
				else if(p){										//p是当前结点r的父结点
					int ps = position(p, r, 0);
					bool b = borrowFromSib(p, r, pos);
					
					//1.3.--------如果该节点不足,且兄弟不可借,则下降-合并------------
					if(!b){
						//将r和其兄弟合并
						deleteList(r->key, r->keyNum, pos);
						r->keyNum--;
						mergeSib(p, ps, false);			
						if(p->keyNum < low){
							cout<<"递归合并"<<endl;
							//删除后,其上层不够,递归合并
							recursionMerge(p);
						}
					}						
				}else{													//p,即r的父为空,则该节点就只有根结点(是叶子并且没有双亲)
					deleteList(r->key, r->keyNum, pos);
					r->keyNum--;
				}
			}
			//2.***********************如果待删除的结点非叶子***********************
			else{
				//int ps = positon(p, r, 0);
				//2.1.如果儿子可借,则从儿子借
				bool b = borrowFromSon(r, pos);
				if(b) cout<<"从儿子借\n";
				//2.2.如果儿子不可借,则看兄弟是否可借
				if(!b){
					//2.2.1.如果兄弟可借,则从兄弟借
					b = borrowFromSib(p, r, pos);
					if(b) cout<<"从兄弟借\n";
					//2.2.2.如果兄弟不可借,下降-合并
					if(!b){
						mergeSib(r, pos, true);
						if(r->keyNum < low){
							//删除后,其上层不够,递归合并
							recursionMerge(r);
						}
					}
				}
			}
		}
	}
	return root;
}

/**
	* x    :待查询关键字;
	* *pos :x在结点中的位置,如果没有,就是待插入位置
	* *p   :返回x所在结点的双亲结点,如果没找到,也返回失败的当前结点
	* 返回查找到的节点,如果没有返回空
	*/
template<class T>
Node<T>* BTree<T>::search(T x, int *pos, Node<T>* &p){
	Node<T>* r = root;
	p = NULL;
	int n, i;
	while(r){
		n = r->keyNum;
		i = 0;
		//找到指针所在位置或指针
		if(x<r->key[0]){//就是第一个儿子指针
			*pos = 0;
			p = r;
			r = r->son[0];
		}else{//后面位置
			while(i<n && x>r->key[i]) i++;
			if(x == r->key[i]){ 
				*pos = i;
				p = r->parent;
				return r;
			}else{
				p = r;
				r = r->son[i];
			}
			*pos = i;
		}
	}
	//如果r是空的话,说明没有找到
	return r;
}

template<class T>
int BTree<T>::height(){
	int h = 0;
	Node<T>* r = root;
	while(r){
		h++;
		r = r->son[0];
	}
	return h;
}


/**
	*非递归打印
	*根据B-树的特点,遍历顺序是关键字从小到大的顺序遍历
	*
	*/
template<class T>
void BTree<T>::printBT(){
	Node<T>* r = root;
	bool isLeaf = true;     //是否是最下层结点
	while(r && r->son[0]){  //如果非一层,则找到起始的结点(最左下结点)
		r = r->son[0];
	}
	
	Node<T>* pre = NULL;		//结点r的遍历前缀结点
	int k = 0;
	while(r){
		if(isLeaf){						//如果是最下层结点,遍历所有结点,之后r指向其父节点
			for(int j=0; j<r->keyNum; j++){
				cout<<r->key[j]<<" ";
			}
			pre = r;
			r = r->parent;
		}else{											//如果不是最下结点,则需要打印其中一个关键字,之后r指向下一个儿子结点
			int keyNum = r->keyNum;
			for(k=0; k<=keyNum; k++){	//注意这里:儿子指针个数=关键字个数+1
				if(r->son[k] == pre){
					if(k != keyNum){ 
						cout<<r->key[k]<<" ";
						pre = r;
						r = r->son[k+1];
					}
					break;
				}
			}
			//root的一个儿子结点结束,开始另一个,则先要找到其最下层左边第一个结点开始遍历(但是只有两层除外)
			if(pre == root && r->son[0]){						//pre是根节点,并且r不是最底层节点
					while(r && r->son[0]){							//使找到起始的结点(最左下结点)
						r = r->son[0];
					}
			}
			//如果是keyNum+1说明当前结点以及指向了最后儿子结点,遍历完了所有儿子,r之后指向其父
			else if(k == keyNum){
				pre = r;
				r = r->parent;
			}
		}
		//判断当前结点是不是最下层结点
		if(r){
			if(!r->son[0]) isLeaf = true;
			else isLeaf = false;
		}
	}
}


template<class T>
void BTree<T>::create(Node<T>* &root){
	T ch;
	cout<<"输入B-树数据(#结束)"<<endl;
	while(cin>>ch){
		if(ch == '#') break;
		insertBT(ch);
	}
}


template<class T>
void BTree<T>::insertList(T *a, int n, T x, int *p){
	int i=0;//待插入位置
	int k=n;
	if(x<a[0]){
		i = 0;
	}else{
		while(i<n && x>a[i]) i++;
	}	
	//插入
	while(k != i){
		a[k] = a[k-1];
		k --;
	}
	a[i] = x;
	*p = i;
}

//插入节点指针到son数组
template<class T>
void BTree<T>::insertPoint(Node<T> *a[], int n, Node<T>* p, int pos){
	if(!p) return;
	int k = n;
	//插入
	while(k != pos){
		a[k] = a[k-1];
		k --;
	}
	a[pos] = p;
}

template<class T>
void BTree<T>::deleteList(T *a, int n, int p){
	if(p<0 || p>=n) return;
	int k = p;
	//删除
	while(k != n-1){
		a[k] = a[k+1];
		k ++;
	}
}							

template<class T>
void BTree<T>::deletePoint(Node<T> *a[], int n, int p){
	if(p<0 || p>=n) return;
	int k = p;
	//Node<T>* r = a[p];
	//删除
	while(k != n-1){
		a[k] = a[k+1];
		k ++;
	}
	//delete r;
}

/**
	* *parent:结点p的父亲结点 
	* *p		 :待查询的结点p
	* key    :待查询的关键字key
	* 返回p在parent的位置; 或者key在parent的位置; 如果没找到返回-1
	* 注:如果p空,则是按关键字查询,否则是按结点查询(优先结点p查询,不能同时查询两个)
	*/
template<class T>
int BTree<T>::position(Node<T>* parent, Node<T>* p, T key){
	int pos = 0;
	if(!parent) return -1;
	int n = parent->keyNum;
	//按关键字查询
	if(p == NULL){
		while(pos < n && key != parent->key[pos]) pos++;
		if(pos == n) pos = -1;
	}else{
		if(p->parent != parent) throw "输入不合法";
		while(pos <= n && p != parent->son[pos]) pos++;
		if(pos == n+1) pos = -1;
	}
	return pos;
}

/**
	* 分裂-提升结点p(注:由B-树的特点可以知道,插入的结点必定是在最低的结点(即没有叶子结点),增长是自底向上增长)
	* *root  :根结点
	* *p     :待分裂结点
	* 返回   :分裂后的父节点
	* 注意   :在分裂过程一定不要忘了修改结点的父亲
	*/
template<class T>
Node<T>* BTree<T>::divideTree(Node<T>* &root, Node<T>* &p){
	int mid = 0;
	Node<T>* parent = NULL;
	Node<T>* t;
	if(p && p->keyNum >= m){
		mid = (p->keyNum)/2;				//找到结点p关键字的中间位置
		parent = p->parent;					//找到结点p的父节点,如果存在,则插入父节点;否则,新建节点,作为新父节点
		if(!parent){								//无父亲
			int i=0;
			//新根结点
			Node<T>* r = new Node<T>;
			r = new Node<T>;
			r->keyNum = 1;
			r->parent = NULL;
			r->key[0] = p->key[mid];
			
			//右结点
			Node<T>* right = new Node<T>;
			right->keyNum = (p->keyNum)-1-mid;
			right->parent = r;
			for(i=0; i<mid; i++){
				right->key[i] = p->key[mid+1+i];
				right->son[i] = p->son[mid+1+i];
			}
			right->son[i] = p->son[mid+1+i];
			
			//左结点
			Node<T>* left = new Node<T>;
			left->keyNum = mid;
			left->parent = r;
			for(i=0; i<left->keyNum; i++){
				left->key[i] = p->key[i];
				left->son[i] = p->son[i];
			}
			left->son[i] = p->son[i];
			
			(r->son)[0] = left;
			(r->son)[1] = right;
			modifyParent(left);
			modifyParent(right);
			root = r;
			parent = r;
		}else{												//有父亲
			//右结点
			int i;
			Node<T>* right = new Node<T>;
			right->keyNum = (p->keyNum)-1-mid;
			right->parent = parent;
			for(i=0; i<mid; i++){
				right->key[i] = p->key[mid+1+i];
				right->son[i] = p->son[mid+1+i];
			}
			right->son[i] = p->son[mid+1+i];
			
			//左结点
			Node<T>* left = new Node<T>;
			left->keyNum = mid;
			left->parent = parent;
			for(i=0; i<left->keyNum; i++){
				left->key[i] = p->key[i];
				left->son[i] = p->son[i];
			}
			left->son[i] = p->son[i];
			
			int pos = 0;
			//修改父节点
			insertList(parent->key, parent->keyNum, p->key[mid], &pos);
			parent->keyNum++;
			//在父的son数组中插入新结点的左右指针
			//注意:首先应该用left替换pos位置的废弃指针———因为它指向的节点提升了,然后插入right
			parent->son[pos] = left;
			insertPoint(parent->son, parent->keyNum+1, right, pos+1);
			modifyParent(left);
			modifyParent(right);
		}
		delete p;
	}
	return parent;
}

/**
	*当分裂-提升之后修改结点的父亲
	*p : 已经经过分裂-提升之后的新的双亲
	*需要修改的是p的所有儿子的双亲,不在是原来的双亲(已经delete)
	*/
template<class T>
void BTree<T>::modifyParent(Node<T>* &p){
	//p存在并且有孩子
	if(p && p->son[0]){
		for(int i=0; i<p->keyNum+1; i++){
			p->son[i]->parent = p;
		}
	}
}

//递归删除
template<class T>
void BTree<T>::release(Node<T>* &root){
	if(root){
		for(int i=0; i<=root->keyNum; i++){
			release(root->son[i]);
		}
		delete root;
	}
}

//递归打印
template<class T>
void BTree<T>::printBT(Node<T>* root){
	if(root){
		for(int i=0; i<root->keyNum; i++){
			printBT(root->son[i]);
			cout<<root->key[i]<<" ";
		}
		printBT(root->son[root->keyNum]);
	}
}

/**
	* 从兄弟借元素(如果存在,否则什么都不做)
	* parent: p的父节点
	* p 		:有待删除元素的节点
	* ps    : 待删除元素在p中的位置
	*注:parent是p的双亲
	*如果存在兄弟可借,则借并返回true,否则false
	*/
template<class T>
bool BTree<T>::borrowFromSib(Node<T>* &parent, Node<T>* p, int ps){
	bool flag = false, haveSon = false;
	if(!p) return flag;
	if(p->parent != parent) throw "输入参数有误!";
	Node<T>* r, *s;
	T k;
	int low = m%2==0 ? m/2-1 : m/2; 
	int pos = position(parent, p, 0);
	int i = 0, t=0;
	//先找到可借的兄弟
	for(i=0; i<=parent->keyNum; i++){
		r = parent->son[i];
		if(r->keyNum > low){ 
			flag = true;
			break;
		}
	}
	if(r->son[0]) haveSon = true;
	if(i <= parent->keyNum){
		if(i>pos){//找到的兄弟位于p的右边
			do{
				k = parent->key[i-1];
				parent->key[i-1] = r->key[0];
				deleteList(r->key, r->keyNum, 0);
				s = r->son[0];
				deletePoint(r->son, r->keyNum+1, 0);
				r->keyNum--;
				i--;
				r = parent->son[i];
				insertList(r->key, r->keyNum, k, &t);
				r->keyNum++;
				insertPoint(r->son, r->keyNum+1, s, r->keyNum);
			}while(r != p);
			//插入的位置都是在尾部,故而不用管t
			if(haveSon){
				mergeSib(p, ps, true);
			}else{
				deleteList(r->key, r->keyNum, ps);
				r->keyNum--;
			}
		}else{		//位于左边
			do{
				k = parent->key[i];
				parent->key[i] = r->key[r->keyNum-1];
				deleteList(r->key, r->keyNum, r->keyNum-1);
				s = r->son[r->keyNum];
				deletePoint(r->son, r->keyNum+1, r->keyNum);
				r->keyNum--;
				i++;
				r = parent->son[i];
				insertList(r->key, r->keyNum, k, &t);
				r->keyNum++;
				insertPoint(r->son, r->keyNum+1, s, 0);
			}while(r != p);
			//插在待删除位置前(这是肯定满足的,因为插入的时候都是0位置)
			if(t <= ps) ps++;
			if(haveSon){
				mergeSib(p, ps, true);
			}else{
				deleteList(r->key, r->keyNum, ps);
				r->keyNum--;
			}
		}
	}
	return flag;
}

/**
	*功能  :删除父亲结点元素,如果儿子充足,则从儿子借
	*parent:待删除元素所在结点
	*pos   :待删除元素的位置
	*返回  :如果找到合适son就执行操作并返回true,否则false
	*/
template<class T>
bool BTree<T>::borrowFromSon(Node<T>* &parent, int pos){
	bool flag = false;
	bool haveSon = false;
	if(!parent || pos<0 || pos>=parent->keyNum) throw "参数有误!";
	if(!parent->son[0]) return flag;
	Node<T>* r, *s;
	T k;
	int low = m%2==0 ? m/2-1 : m/2; 
	//寻找合适的儿子
	int i=0,t=0;
	for(i=0; i<=parent->keyNum; i++){
		r = parent->son[i];
		if(r->keyNum > low){ 
			flag = true;
			break;
		}
	}
	if(r->son[0]) haveSon = true;
	if(i <= parent->keyNum){
		if(i>pos){//如果儿子在右边
				while(i != pos+1){
					k = parent->key[i-1];
					parent->key[i-1] = r->key[0];
					deleteList(r->key, r->keyNum, 0);
					s = r->son[0];
					deletePoint(r->son, r->keyNum+1, 0);
					r->keyNum--;
					i--;
					r = parent->son[i];
					insertList(r->key, r->keyNum, k, &t);
					r->keyNum++;
					insertPoint(r->son, r->keyNum+1, s, r->keyNum);
				}
				if(haveSon){
					parent->key[pos] = r->key[0];
					deleteList(r->key, r->keyNum, 0);
					s = r->son[0];
					deletePoint(r->son, r->keyNum+1, 0);
					r->keyNum--;
					Node<T>* q = parent->son[pos]->son[parent->son[pos]->keyNum];
					merge2Node(q, s);
				}else{
					parent->key[pos] = r->key[0];
					deleteList(r->key, r->keyNum, 0);
					r->keyNum--;
				}
		}else{
			while(i != pos){
				k = parent->key[i];
				parent->key[i] = r->key[r->keyNum-1];
				deleteList(r->key, r->keyNum, r->keyNum-1);
				s = r->son[r->keyNum];
				deletePoint(r->son, r->keyNum+1, r->keyNum);
				r->keyNum--;
				i++;
				r = parent->son[i];
				insertList(r->key, r->keyNum, k, &t);
				r->keyNum++;
				insertPoint(r->son, r->keyNum+1, s, 0);
			}
			if(haveSon){
				parent->key[pos] = r->key[r->keyNum-1];
				deleteList(r->key, r->keyNum, r->keyNum-1);
				s = r->son[r->keyNum];
				deletePoint(r->son, r->keyNum+1, r->keyNum);
				r->keyNum--;
				Node<T>* m = parent->son[pos+1]->son[0];
				merge2Node(s , m);
				parent->son[pos+1]->son[0] = s;
				modifyParent(parent->son[pos+1]->son[0]);
			}else{
				parent->key[pos] = r->key[r->keyNum-1];
				deleteList(r->key, r->keyNum, r->keyNum-1);
				r->keyNum--;
			}
		}
	}
	return flag;
}

/**
	*将q合并到p之后
	*/
template<class T>
void BTree<T>::merge2Node(Node<T>* &p, Node<T>* q){
	if(!p || !q) return;
	int t, i=0;
	for(i=0; i<q->keyNum; i++){
		insertList(p->key, p->keyNum, q->key[i], &t);
		p->keyNum++;
		insertPoint(p->son, p->keyNum+1, q->son[i], p->keyNum);
	}
	insertPoint(p->son, p->keyNum+1, q->son[i], p->keyNum+1);
	delete q;
}

/**
	* 合并parent所在pos位置的左右孩子,并将key[pos]下降到合并结点中(下降-合并)
	* 注:下降之后,并且删除了父结点中的key,它在合并结点中
	* parent : 待合并孩子的双亲结点
	* pos    :在parent中孩子指针位置,pos位置的孩子和其左或右孩子是待合并的
	* ***如果key[pos]是待删除的则设置flag=true
	*/
template<class T>
void BTree<T>::mergeSib(Node<T>* &parent, int pos, bool flag){
	if(!parent || pos<0 || pos>parent->keyNum) return;
	if(!parent->son[0]) throw "参数有误!";
	//将r和其兄弟合并
	int t=0;
	int pos1,pos2;
	if(pos == parent->keyNum){ 
		pos1 = pos-1;
		pos2 = pos;
	}else{ 
		pos1 = pos;
		pos2 = pos+1;
	} 
	Node<T>* r = parent->son[pos1];
	Node<T> *x = parent->son[pos2];
	if(x){
			//将父结点放入左儿子(下降)
			insertList(r->key, r->keyNum, parent->key[pos1], &t);
			r->keyNum++;
			
			//将右兄弟中的关键字和指针都放到左儿子中(合并)
			int i=0;
			while(x->keyNum != 0){
				insertPoint(r->son, r->keyNum+1, x->son[i++], r->keyNum);
				insertList(r->key, r->keyNum, x->key[0], &t);
				r->keyNum++;
				deleteList(x->key, x->keyNum, 0);
				x->keyNum--;
			}
			insertPoint(r->son, r->keyNum+1, x->son[i], r->keyNum);
			delete x;			
			
			//如果flag是true,则要删除下降的key
			if(flag){
				int pp = position(r, NULL, parent->key[pos1]);
				if(!r->son[0]){ 
					deleteList(r->key, r->keyNum, pp);
					r->keyNum--;
				}else{
					mergeSib(r, pp, true);
				}
			}
			
			//删除父节点的关键字和指针
			deleteList(parent->key, parent->keyNum, pos1);
			deletePoint(parent->son, parent->keyNum+1, pos2);
			parent->keyNum--;
			
			if(parent->keyNum == 0){
				if(parent == root) root = r;
				parent = r;
				parent->parent = NULL;
			}
			modifyParent(r);
	}
}

//递归合并,如果p不够就要向上合并
template<class T>
void BTree<T>::recursionMerge(Node<T>* &p){
	int low = m%2==0 ? m/2-1 : m/2; 
	if(p && p->keyNum<low){
		//看是否可以从兄弟借,若可借,则借,否则下降-合并
		if(!borrowFromSib(p->parent, p, -1)){
			cout<<"不可借"<<endl;
			//下降-合并
			int i = position(p->parent, p, 0);
			mergeSib(p->parent, i, false);			
			recursionMerge(p->parent);
		}
	}
}

/**
	* 递归插入
	* *p  : 暂存插入位置的节点
	* *pos:暂存插入的位置
	
template<class T>
void BTree<T>::insertBT(Node<T>* &r, T x, int pos){
	if(!r){
		r = new Node<T>;
		r->keyNum = 1;
		r->parent = NULL;
		(r->key)[0] = x;
		return;
	}else{
		pos = 0;
		//在r上搜索插入位置
		if(x<r->key[0]){
				pos = 0;
		}else{//后面位置
				while(pos<r->keyNum && x>r->key[pos]) pos++;
				if(x == r->key[pos]) return;
		}
		//是否递归插入,如果在叶子结点,就找到了插入位置,否则递归插入
		if(!r->son[pos]){//找到了插入的节点
			cout<<"插入结点"<<endl;	
			insertList(r->key, r->keyNum, x, &pos);
			r->keyNum++;
			if(r->keyNum >= m){
				cout<<"分裂-提升"<<endl;
				//divideTree(root, r);
				Node<T>* parent = divideTree(root, r);
				while(parent && parent->keyNum >= m){
					cout<<"继续提升!"<<endl;
					parent = divideTree(root, parent);
				}
			}
			return;
		}else{//没有找到插入结点,递归插入
			insertBT(r->son[pos], x, pos);
		}
	}
}
*/

 

 c.main.cpp

 

#include <iostream>
#include "btree.cpp"
using namespace std;

//注意35是‘#’,故而输入的时候注意
int main(){
	//int a[] = {23, 40, 12, 50, 80, 42, 6, 7};//, 47, 90, 95
	//int a[] = {23,50,80,100,60,55,70,85,87,57,20,89,90,110,52,59,53, 111,114,24,25,26};//, 111,114,115
	int a[] = {23,50,80,100,60,55,70,85,87,57,20,89,90,110,52,59,53,21};//
	BTree<int> bt(5, a, 18);
	//BTree<int> bt(3);
	
	cout<<"非递归打印"<<endl;
	bt.printBT();
	
	cout<<"\n递归打印"<<endl;
	Node<int>* root = bt.getRoot();
	bt.printBT(root);
	
	cout<<"\n高度:"<<bt.height()<<endl;
	
	cout<<"\n搜索"<<endl;
	Node<int>* p;
	int pos = 0;
	p = bt.search(100, &pos, p);
	if(p){
		for(int i=0; i<p->keyNum; i++) cout<<p->key[i]<<" ";
		cout<<"\n位置"<<pos<<" "<<p->keyNum<<endl;
	}
	
	/*
	cout<<"\n删除叶子,并且充足"<<endl;
	bt.deleteBT(54);
	bt.printBT();
	
	cout<<"\n删除叶子,叶子不足,兄弟可借(借在左或右)"<<endl;
	bt.deleteBT(23);
	bt.printBT();
	
	cout<<"\n删除叶子,叶子不足,兄弟不可借"<<endl;
	root = bt.deleteBT(70);
	bt.printBT();
	cout<<endl;
	bt.printBT(root);
	
	cout<<endl;
	cout<<root->keyNum<<endl;
	for(int i=0; i<root->keyNum; i++){
		cout<<root->key[i]<<" ";
	}
	cout<<endl;
	for(int i=0; i<=root->keyNum; i++){
		cout<<root->son[i]->keyNum<<endl;
		for(int j=0; j<root->son[i]->keyNum; j++){
			cout<<root->son[i]->key[j]<<" ";
		}
		cout<<endl;
	}
	cout<<endl;
	*/
	
	/*
	cout<<"\n删除非叶子,儿子可借(借在左或右)"<<endl;
	root = bt.deleteBT(55);
	cout<<root->key[0]<<endl;
	for(int i=0; i<root->keyNum+1; i++){
		for(int j=0; j<root->son[i]->keyNum; j++){
			cout<<root->son[i]->key[j]<<" ";
		}
		cout<<endl;
	}
	bt.printBT(root);
	cout<<endl;
	bt.printBT();
	p = bt.search(53, &pos, p);
	//p = p->son[p->keyNum];
	cout<<p->keyNum<<endl;
	for(int i=0; i<p->keyNum+1; i++){
		for(int j=0; j<p->son[i]->keyNum; j++){
			cout<<p->son[i]->key[j]<<" ";
		}
		cout<<endl;
	}
	
	
	cout<<"\n删除非叶子,儿子不可借,兄弟不可借"<<endl;
	root = bt.deleteBT(85);
	bt.printBT(root);
	cout<<"\nroot:"<<root->keyNum<<endl;
	bt.printBT();
	
	
	cout<<"\n删除非叶子,儿子不可借,兄弟可借(借在左或右)"<<endl;
	bt.deleteBT(85);
	bt.printBT();
	*/
	return 0;
}
 

 

 

  • 大小: 2.7 KB
  • 大小: 30.4 KB
  • 大小: 31.3 KB
  • 大小: 20 KB
分享到:
评论

相关推荐

    基于 B- 树实现的图书管理系统

    《基于B-树实现的图书管理系统》 在计算机科学领域,数据结构的选择对系统的性能有着至关重要的影响。在这个图书管理系统中,我们运用了B-树(B-tree)这一经典的数据结构,来高效地管理和检索图书信息。B-树是...

    B-树 C++实现 基本功能

    "BMT"可能是"B-Tree Main Test"的缩写,这可能是一个主测试程序,用来验证B-树实现的正确性和性能。 在具体实现时,需要注意的是,C++标准库并不直接支持B-树这样的数据结构,因此我们需要自己编写代码来实现。同时...

    B-树实现的中文词典

    《B-树实现的中文词典》 在信息技术领域,数据结构是构建高效算法的基础,而B-树(B-tree)作为一种自平衡的查找树,因其高效的数据存储和检索特性,常被用于数据库和文件系统中。在这个项目中,B-树被用来实现一个...

    图书管理系统 B-树实现目录索引.rar

    《图书管理系统 B-树实现目录索引》 在IT领域,数据结构是计算机科学的基础,B-树(B-Tree)作为一种自平衡的查找树,常用于数据库和文件系统中,以实现高效的检索效率。本项目是针对图书管理系统的目录索引实现,...

    B-树的实现,B-树的分析,B-树的代码

    ### B-树的实现与分析 B-树是一种自平衡的树数据结构,常用于数据库和文件系统中,因其能够高效地支持查找、插入和删除操作,并且在磁盘读写方面具有很好的性能。本文将从给定的代码片段出发,深入解析B-树的关键...

    B- B-树算法实现

    在本项目中,我们将深入探讨B- B-树(通常指的是B-树或B+树)的实现,并以C语言为编程工具,结合VC6.0开发环境进行实践。 B-树的核心特性在于它的分层结构,每个节点可以有多个子节点,这使得它在处理大量数据时...

    B.rar_B-树索引_B树_b tree_b tree java_java B-Tree

    标题中的"B.rar_B-树索引_B树_b tree_b tree java_java B-Tree"表明这是一个关于B-树实现的压缩文件,其中包含了用Java语言编写的B-树索引代码,并且含有详细的注释。这为学习和理解B-树提供了实践示例。 首先,...

    山东大学数据结构实验B-树(java实现)

    在“B-TreeProject”这个项目中,你将会看到一个完整的B-树实现,包括BTreeNode类、插入和删除的函数,以及可能的测试用例。通过阅读和运行代码,你可以更深入地理解B-树的工作原理,并学习如何在实际编程中应用数据...

    数据结构实验报告-查找-B-树基本操作的实现 实验报告(含完整代码及测试)

    **数据结构实验报告 - B-树基本操作的实现** 本次实验主要关注B-树这一重要的数据结构,它在数据库和文件系统中有着广泛的应用。B-树是一种自平衡的多路搜索树,能够保持数据排序并高效地进行查找、插入和删除操作...

    B-树的实现

    3. **函数声明**: 提供的代码还包含了若干个函数的声明,这些函数用于实现B-树的各种操作: - `btreesearch`: 查找键值。 - `btreeinsert`: 插入键值。 - `btreedelete`: 删除键值。 - `height`: 计算树的高度。...

    B-树的源代码

    在这个“B-树的源代码”项目中,开发者使用C++语言实现了B-树的基本操作,包括构造、查找、插入和删除节点。C++是一种广泛应用的面向对象编程语言,具有高效和灵活的特点,适合编写这种底层数据结构的代码。 B-树的...

    B-树 B+树 源代码 C++ 数据结构

    本项目提供的源代码是C++实现的B-树和B+树,有助于学习者深入理解这两种数据结构的内部机制。 首先,B-树(Balanced Tree)是一种自平衡的多路搜索树,它的每个节点可以有多个子节点,通常为2到32个。B-树的主要...

    数据结构基础内容与B-树的详解

    2. **树形结构**:如二叉树、平衡树和B-树。二叉树是最简单的树形结构,每个节点最多有两个子节点。平衡树,如AVL树和红黑树,是为了保持搜索效率而设计的,它们确保任何节点的左右子树高度差不超过1。B-树是一种自...

    数据结构实验报告-查找-B-树基本操作的实现2017.docx

    **数据结构实验报告 - B-树基本操作的实现** 本次实验是关于B-树的数据结构操作,主要涉及插入、删除、查找以及层次遍历等基本功能。B-树是一种自平衡的多路查找树,广泛应用于数据库和文件系统中,以高效地处理...

    B-树及其基本操作(插入和删除)详解1

    B-树是一种自平衡的树数据结构,主要用于数据库和文件系统中,以高效地存储和检索大量数据。在B-树中,每个节点可以拥有多个子节点,最多可...在实际应用中,Java等编程语言可以通过实现B-树的数据结构来提供这些功能。

    动态打印B-树代码

    本教程将详细阐述如何动态地打印B-树,以及如何实现其基本操作:插入、创建、删除和查找。 首先,B-树是一种多路搜索树,每个节点可以有多个子节点。它的特性在于所有叶子节点都在同一层,且每个节点存储的关键字...

    B-树课程设计.doc

    本次课程设计的目标是理解和实现B-树数据结构,这是一种高效的数据存储和检索方法,尤其适用于大量数据的管理和操作。学生将在Windows环境下使用Devc++开发软件进行编程,最低硬件要求为奔腾处理器和32MB内存,但...

    B-树源码及报告文档

    "完整的B-树实现源码,包括注释、详细讲解、相关的报告文档及ppt" 提供的资源可以帮助我们深入理解B-树的内部工作机制。源码提供了直观的实现细节,注释有助于理解代码逻辑,报告文档和PPT则可能包含理论介绍、算法...

    数据结构课程设计B-树

    通过以上分析可以看出,这段代码主要实现了B-树的基本功能,包括节点结构体的定义、查找操作以及插入操作。其中涉及到了关键的B-树维护操作,例如节点分裂和新建根节点,这些操作确保了B-树能够在保持平衡的同时支持...

    B-Trees 的实现及分析

    根据给定的信息,本文将详细解析B-树的实现与分析。B-树是一种非常重要的数据结构,在数据库索引、文件系统以及其他需要高效查找、插入和删除操作的应用场景中广泛使用。 ### B-树的基本概念 B-树是一种自平衡的多...

Global site tag (gtag.js) - Google Analytics