C B-Tree实现

一、B-tree基本概念

https://www.cnblogs.com/nullzx/p/8729425.html

二、代码实现

#include<bits/stdc++.h>
using namespace std;
#define MAX_M 10
#define MAX_KEYNUM m - 1
#define MIN_KEYNUM (m + 1) / 2 - 1
typedef int KeyTpye;
int m = 3;
typedef struct node {
	int keynum;
	KeyTpye key[MAX_M];//最多有m-1个关键字,最少有 (m+1)/2 - 1 个关键字
	struct node* parent;
	struct node* ptr[MAX_M];//最多有m个子树,最少有 (m+1)/2 个子树
}BTNode;
BTNode* Root = NULL;
void Split(BTNode* T) {
	int mid = MIN_KEYNUM + 1;//从中间位置分裂
	BTNode* right = new BTNode;//右边部分的关键字放在一个新生成的节点中,
	memset(right->ptr, NULL, sizeof(right->ptr));
	right->keynum = T->keynum - mid;
	for (int i = 1;i <= right->keynum;i++) right->key[i] = T->key[mid + i];
	for (int i = 0;i <= right->keynum;i++) {
		right->ptr[i] = T->ptr[mid + i];
		if (right->ptr[i])  right->ptr[i]->parent = right;
	}
	T->keynum = mid - 1;//左边部分的关键字保留在该节点中
	if (!T->parent) {//如果没有父节点
		T->parent = new BTNode;
		memset(T->parent->ptr, NULL, sizeof(T->parent->ptr));
		T->parent->keynum = 1;
		T->parent->parent = NULL;
		T->parent->key[1] = T->key[mid];
		T->parent->ptr[1] = right;
		T->parent->ptr[0] = T;
		right->parent = T->parent;
		Root = T->parent;
	}
	else {
		int pos = 1;
		while (pos <= T->parent->keynum && T->key[mid] > T->parent->key[pos]) pos++;
		for (int i = T->parent->keynum;i >= pos;i--) {
			T->parent->key[i + 1] = T->parent->key[i];
			T->parent->ptr[i + 1] = T->parent->ptr[i];
		}
		T->parent->key[pos] = T->key[mid];
		T->parent->ptr[pos] = right;
		T->parent->keynum++;
		right->parent = T->parent;
		if (T->parent->keynum > MAX_KEYNUM) {//如果插入之后导致keynum大于最大关键字的数量
			Split(T->parent);//分裂
		}
	}
}
void Insert(BTNode* T, KeyTpye x) {
	if (!Root) {//如果根节点为空
		T = new BTNode;
		memset(T->ptr, NULL, sizeof(T->ptr));
		T->keynum = 1;
		T->key[1] = x;
		T->parent = NULL;
		Root = T;
		return;
	}
	int pos = 1;
	while (pos <= T->keynum && x > T->key[pos]) pos++;
	if (pos <= T->keynum && x == T->key[pos]) {
		cout << "\n元素已存在!\n";
		return;
	}
	if (!T->ptr[pos - 1]) {//如果该节点是叶子结点,则直接插入
		for (int i = T->keynum;i >= pos;i--) T->key[i + 1] = T->key[i];
		T->key[pos] = x;
		T->keynum++;
		if (T->keynum > MAX_KEYNUM) {//如果插入之后导致keynum大于最大关键字的数量
			Split(T);//分裂
		}
	}
	else  Insert(T->ptr[pos - 1], x);//如果该节点不是叶子结点,则要向下继续寻找
}
void dfs(BTNode* T) {
	if (T) {
		int i;
		for (i = 0;i < T->keynum;i++) {
			dfs(T->ptr[i]);
			cout << T->key[i + 1] << " ";
		}
		dfs(T->ptr[i]);
	}
}
KeyTpye Findmin(BTNode* T) {
	while (T->ptr[0]) {
		T = T->ptr[0];
	}
	return T->key[1];
}
int Delete_From_Brother(BTNode* T, const int pos) {//pos是已删除的数值在叶子结点的位置
	int ptrpos = 0, i;//ptrpos是叶子结点在其父节点ptr数组中的位置
	while (T->parent->ptr[ptrpos] != T) ptrpos++;
	BTNode* leftbrother, * rightbrother;
	if (ptrpos == 0) leftbrother = NULL, rightbrother = T->parent->ptr[1];//如果该节点没有左兄弟
	else if (ptrpos == T->parent->keynum) leftbrother = T->parent->ptr[T->parent->keynum - 1], rightbrother = NULL;//没有右兄弟
	else leftbrother = T->parent->ptr[ptrpos - 1], rightbrother = T->parent->ptr[ptrpos + 1];
	//在将左右兄弟节点中的数值移过去的时候,还要将其子树的指针也移动过去
	if (leftbrother && leftbrother->keynum > MIN_KEYNUM) {//如果有左兄弟,ptrpos >= 1
		for (i = T->keynum;i >= 1;i--) {
			T->key[i + 1] = T->key[i];//数据往后移
			T->ptr[i + 1] = T->ptr[i];
		} 
		T->ptr[1] = T->ptr[0];
		T->key[1] = T->parent->key[ptrpos];//把左兄弟中最大的给其父节点,父节点的值下去,要放在该节点的最左面
		T->ptr[0] = leftbrother->ptr[leftbrother->keynum];//左兄弟最大关键字的右指针 赋值给从父节点下去的关键字的左指针
		T->keynum++;
		T->parent->key[ptrpos] = leftbrother->key[leftbrother->keynum];
		leftbrother->keynum--;
		return -1;
	}
	if (rightbrother && rightbrother->keynum > MIN_KEYNUM) {//如果有右兄弟,ptrpos < T->parent->keynum
		T->keynum++;
		T->key[T->keynum] = T->parent->key[ptrpos + 1];//把右兄弟中最小的给其父节点,父节点的值下去,放在最右面
		T->ptr[T->keynum] = rightbrother->ptr[0];//右兄弟中最小的关键字的左指针 赋值给从父节点下去的关键字的右指针
		T->parent->key[ptrpos + 1] = rightbrother->key[1];
		rightbrother->ptr[0] = rightbrother->ptr[1];
		for (i = 2;i <= rightbrother->keynum;i++) {
			rightbrother->key[i - 1] = rightbrother->key[i];
			rightbrother->ptr[i - 1] = rightbrother->ptr[i];
		}
		rightbrother->keynum--;
		return -1;
	}
	return ptrpos;
}
void Merge(BTNode* T, const int ptrpos) {
	BTNode* leftbrother, * rightbrother, * p;
	if (ptrpos == 0) leftbrother = NULL, rightbrother = T->parent->ptr[1];//如果该节点没有左兄弟
	else if (ptrpos == T->parent->keynum) leftbrother = T->parent->ptr[T->parent->keynum - 1], rightbrother = NULL;//没有右兄弟
	else leftbrother = T->parent->ptr[ptrpos - 1], rightbrother = T->parent->ptr[ptrpos + 1];
	int i, k;
	bool flag;//有左兄弟为0,否则为1
	p = new BTNode;
	p->parent = T->parent;
	memset(p->ptr, NULL, sizeof(p->ptr));
	if (leftbrother) {//如果有左兄弟,ptrpos >= 1
		flag = false;
		p->keynum = leftbrother->keynum + T->keynum + 1;//合并 删除关键字后的该节点 与其 左兄弟节点 以及 父节点中用以分割二者的关键字
		i = 1; k = 1;
		p->ptr[0] = leftbrother->ptr[0];
		if (p->ptr[0]) p->ptr[0]->parent = p;
		while (i <= leftbrother->keynum) {
			p->key[k] = leftbrother->key[i];
			p->ptr[k] = leftbrother->ptr[i];
			if (p->ptr[k]) p->ptr[k]->parent = p;
			k++, i++;
		}
		p->key[k] = T->parent->key[ptrpos], p->ptr[k] = T->ptr[0];
		if (p->ptr[k]) p->ptr[k]->parent = p;
		i = 1; k++;
		while (i <= T->keynum) {
			p->key[k] = T->key[i];
			p->ptr[k] = T->ptr[i];
			if (p->ptr[k]) p->ptr[k]->parent = p;
			k++, i++;
		}
		delete[]leftbrother;
		delete[]T;
		T = p;
		for (i = ptrpos + 1;i <= T->parent->keynum;i++) {//把当前节点覆盖了,其他数据前移
			T->parent->key[i - 1] = T->parent->key[i];
			T->parent->ptr[i - 1] = T->parent->ptr[i];
		}
		T->parent->ptr[ptrpos - 1] = p;//左孩子被覆盖,p变成了分割它和左兄弟的关键字的后面一个关键字的左子树
		T->parent->keynum--;
	}
	else if (rightbrother) {//如果有右兄弟
		flag = true;
		p->keynum = rightbrother->keynum + T->keynum + 1;
		i = 1; k = 1;
		p->ptr[0] = T->ptr[0];
		if (p->ptr[0]) p->ptr[0]->parent = p;
		while (i <= T->keynum) {
			p->key[k] = T->key[i];
			p->ptr[k] = T->ptr[i];
			if (p->ptr[k]) p->ptr[k]->parent = p;
			k++, i++;
		}
		p->key[k] = T->parent->key[ptrpos + 1], p->ptr[k] = rightbrother->ptr[0];
		if (p->ptr[k]) p->ptr[k]->parent = p;
		i = 1; k++;
		while (i <= rightbrother->keynum) {
			p->key[k] = rightbrother->key[i];
			p->ptr[k] = rightbrother->ptr[i];
			if (p->ptr[k]) p->ptr[k]->parent = p;
			k++, i++;
		}
		delete[]rightbrother;
		delete[]T;
		T = p;
		for (i = ptrpos + 2;i <= T->parent->keynum;i++) {//把右兄弟覆盖了,其他数据前移
			T->parent->key[i - 1] = T->parent->key[i];
			T->parent->ptr[i - 1] = T->parent->ptr[i];
		}
		T->parent->ptr[ptrpos] = p;//把当前节点覆盖了,p变成了分割它和左兄弟的关键字的后面一个关键字的左子树
		T->parent->keynum--;
	}
	if (T->parent->keynum < MIN_KEYNUM) {//如果删除父节点的关键字之后,导致父节点不满足最小关键字数量
		if (T->parent == Root) {//如果父节点是根节点
			if (T->parent->keynum == 0) Root = T;//如果根节点没有关键字了,则令T 为根节点
			return;//否则不需要操作
		}
		int pos;
		if(flag) pos = Delete_From_Brother(T->parent, ptrpos + 1);//如果合并的是右兄弟
		else pos = Delete_From_Brother(T->parent, ptrpos);
		if (pos != -1) Merge(T->parent, pos);
	}
}
void Delete(BTNode* T, KeyTpye x) {
	int pos = 1;
	while (pos <= T->keynum && x > T->key[pos]) pos++;
	if (pos > T->keynum || T->key[pos] != x) {//如果没找到
		Delete(T->ptr[pos - 1], x);
	}
	else {//如果找到了
		if (T->ptr[pos]) {//如果该节点不是叶子结点
			KeyTpye tmp = Findmin(T->ptr[pos]);//找它的分支节点中最小的
			T->key[pos] = tmp;
			Delete(T->ptr[pos], tmp);
		}
		else {//如果是叶子结点
			for (int i = pos + 1;i <= T->keynum;i++) T->key[i - 1] = T->key[i];
			for (int i = pos;i <= T->keynum;i++) T->ptr[i - 1] = T->ptr[i];//删掉它左子树的指针(其实有没有这一步都可以,因为都是在叶子结点上操作的)
			T->keynum--;
			if (T == Root || T->keynum >= MIN_KEYNUM) 	return;
			//如果删完之后关键字数量小于最小关键字数量
			int ptrpos = Delete_From_Brother(T, pos);//如果可以从左右兄弟节点删除,返回-1
			if (ptrpos != -1)  Merge(T, ptrpos);//T 一定不可能是根节点
		}
	}
}
void bfs() {
	BTNode* p;
	queue<BTNode*>q;
	int i, cnt = 1;
	if (Root) {
		q.push(Root);
		q.push(NULL);
	}
	for (i = 0;i <= 43;i++) cout << " ";
	while (!q.empty()) {
		p = q.front();
		q.pop();
		if (p) {
			cout << "| ";
			for (i = 0;i < p->keynum;i++) {
				if (p->ptr[i]) q.push(p->ptr[i]);
				cout << p->key[i + 1] << " ";
			}
			cout << "|";
			if (p->ptr[i]) q.push(p->ptr[i]);
		}
		else {
			if (q.empty()) return;
			cout << endl;
			for (i = 0;i <= 50 - 10 * cnt;i++) cout << " ";
			cnt++;
			q.push(NULL);
		}
	}
}
int main() {
	int i, n;
	KeyTpye x;
	cout << "\n请输入数据规模:";
	cin >> n;
	cout << "\n请输入数据:";
	for (i = 1;i <= n;i++) {
		cin >> x;
		Insert(Root, x);
	}
	//cout << "\n构建完毕!中序遍历为:";
	cout << "\n构建完毕!层次遍历为:";
	cout << endl;
	bfs();
	cout << endl;
	//dfs(Root);
	cout << "\n\n请输入要删除的数据规模:";
	cin >> n;
	while (n--) {
		cout << "\n请输入删除的值:";
		cin >> x;
		Delete(Root, x);
		cout << "\n构建完毕!层次遍历为:";
		cout << endl;
		//cout << "\n删除完毕!中序遍历为:";
		//dfs(Root);
		bfs();
		cout << endl;
	}
}
/*
13
19 15 26 35 7 10 16 20 24 28 33 36 39
*/
/*
17
19 15 30 10 17 26 35 7 14 16 18 20 24 28 33 36 39
*/
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值