B树C++实现

一.B树定义:

结点属性:

1.n 表示存储在结点中的关键字个数
2.n 个关键字以非降序存放
3.isleaf 表示是否是叶节点
4.有n+1个指向孩子的指针ci(i:1 n+1),叶节点不定义属性c
5.关键字key对子树中的关键字范围进行分割
6.每个叶节点有相同的深度即h

定义最小度数:t>=2

1.除根结点外每个结点至少有t-1个关键字,t个孩子。根结点在树非空的情况下,至少有1个关键字。
2.每个结点至多有2*t-1个关键字,至多有2*t个孩子。当有2*t-1个关键字时,称该结点时满的。

高度:


结点:

const int Maxn = 10;
struct Node
{
	int n;
	int key[Maxn];
	Node* C[Maxn + 1];
	bool isleaf;
	Node(int n, bool is) :n(n), isleaf(is) {}
};

类:

class Btree
{
private:
	int t;
	int h;
	Node * root;
	pair<Node*, int> Nsearch(Node* t, int k);
	void split(Node* x, int i, Node* y);
	void Insert_Nonfull(Node* x, int k);
	int Predecessor(Node* y);  //前驱
	int Successor(Node* z);   //后继
	//x的第i个关键字转移到右子节点
	void Shift_Right(Node* x, int i, Node* y, Node* z);
	//x的第i个关键字转移到左子节点
	void Shift_Left(Node* x, int i, Node* y, Node* z);
	void DeleteNon(Node* x, int k);
	//合并y,z与x的第i个关键字->合为一个y
	void Merge(Node* x, int i, Node* y, Node* z);
public:
	pair<Node*, int> search(int k);
	Btree(int tt) { t = tt; h = 1; root = new Node(0, true); }
	Btree() {}
	void Insert(int k);
	void Delete(int k);
	void showNode(Node* t)
	{
		for (int i = 0; i<t->n; i++)
			cout << t->key[i] << '\t';
		cout << endl;
	}
	Node* GetRoot() { return root; }
	int GetHeight() { return h; }
};

二.搜索:

递归实现

pair<Node*, int> Btree::Nsearch(Node* t, int k)//在子树t中查找,返回结点指针和关键字序号(从1开始)
{
	Node* r = root;
	int i = 0;
	while (i<t->n&&t->key[i]<k)//k对应哪一个关键字或哪一个子树(排列为非降序)
		i++;
	if (i < t->n&&t->key[i] == k)//找到
	{
		return pair<Node*, int>(t, i + 1);
	}
	else if (t->isleaf)//查找失败
	{
		cout << k << "SF!!!\n";
		return pair<Node*, int>(nullptr, -1);
	}
	else
		return Nsearch(t->C[i], k);//递归查找
}
pair<Node*, int> Btree::search(int k)
{
	return Nsearch(root, k);
}

二.插入:

分裂:

//传入一个非满的结点x,同时x.C[i]指向的结点为满的。将x.C[i]第t个结点上移到x成为分割y和z的关键字,x.C[i]分裂为两部分,各自有t-1个关键字
//此时两个结点孩子总数为2*(t)=2*t,与分裂前没有变化。新的结点z作为x新的孩子,排在y之后。
void Btree::split(Node* x, int i, Node* y)
{
	Node* z = new Node(t - 1, y->isleaf);//一个新的结点
	y->n = t - 1;//更新y的大小
	for (int j = 0; j < t - 1; j++)//后t-1个归z
		z->key[j] = y->key[j + t];
	if (!y->isleaf)
	{
		for (int j = 0; j < t; j++)
			z->C[j] = y->C[j + t];
	}
	for (int j = x->n; j > i; j--)  //x下标第i到第n-1的关键字后移1位
	{
		x->key[j] = x->key[j - 1];
	}
	x->key[i] = y->key[t - 1];
	for (int j = x->n + 1; j > i+1; j--)//x下标第i+1到第n孩子后移一位
	{
		x->C[j] = x->C[j - 1];
	}
	x->C[i+1] = z;
	x->n++;
}

插入:

//辅助过程,要求x非满
void Btree::Insert_Nonfull(Node* x, int k)
{
	int i = x->n - 1;
	if (x->isleaf)//x为叶节点(非满)
	{
		while (i >= 0 && k < x->key[i])//从后找到插入位置,向后移动调整关键字
		{
			x->key[i + 1] = x->key[i];
			i--;
		}
		x->key[i + 1] = k;
		x->n++;
	}
	else
	{
		while (i >= 0 && k < x->key[i])//决定向哪个子结点递归
			i--;
		i++;//目标子结点在关键字之后,序号比关键字大1
		if (x->C[i]->n == 2 * t - 1)//分裂
		{
			split(x, i, x->C[i]);
			if (k > x->key[i])
				i++;
		}
		Insert_Nonfull(x->C[i], k);
	}
}
//沿着树单程向下插入关键字
//当根结点为满。分裂根结点,第t个关键字对应结点成为子女的根,有两个孩子。
void Btree::Insert(int k)
{
	Node* r = root;
	if (r->n == 2 * t - 1)
	{
		root = new Node(0, false);
		root->C[0] = r;//初始时新根结点为空,分裂时结点上移到根结点
		split(root, 0, r);
		h++;
		Insert_Nonfull(root, k);
	}
	else
		Insert_Nonfull(r, k);
}

三.删除:

从x中删除k,必须保证无论何时x递归调研自身时,x中关键字个数至少为t,比通常最小关键字树多一个。
分如下情况:

Case1:k在结点x中,且x为叶节点,删除k;
Case2:k在结点x中,且x为内部结点
          a:若结点x中前于k的子结点y至少有t个关键字,找出k在y中的前驱。递归的删除前驱,并以前驱在x中代替k。
          b:对称的,若y只有t-1个结点,则检查x中后于k的结点z,寻找后继。
          c:若y和z均只有t-1个关键字,将k和z全部合并进y,释放z并递归的在y中删除k。
Case3:k不在x中,应确定包含k的子树x.C[i]。若x.C[i]只有t-1个关键字,则:
         a:其相邻的兄弟结点至少有t个关键字,将x的某一个关键字降至x.C[i],将相邻兄弟结点中的一个关键字升到x。
         b:若所有相邻兄弟结点均只有t-1个关键字,将x.C[i]与一个兄弟合并,x的一个关键字移到新合并的结点。


注意i是代表第几个还是0开始的索引。
int Btree::Predecessor(Node* y)  //前驱
{
	Node* x = y;
	int i = x->n;
	while (!x->isleaf)
	{
		x = x->C[i];
		i = x->n;
	}
	return x->key[i - 1];
}
int Btree::Successor(Node* z)   //后继
{
	Node* x = z;
	while (!x->isleaf)
	{
		x = x->C[0];
	}
	return x->key[0];
}
//x的第i个关键字转移到右子节点
void Btree::Shift_Right(Node* x, int i, Node* y, Node* z)//i-1才为索引
{
	int j = z->n;
	while (j > 0)
	{
		z->key[j] = z->key[j - 1];
		j--;
	}
	z->key[0] = x->key[i - 1];
	x->key[i - 1] = y->key[y->n - 1];
	z->n++;
	if (!z->isleaf)
	{
		j = z->n;
		while (j > 0)
		{
			z->C[j] = z->C[j - 1];
		}
		z->C[0] = y->C[y->n];
	}
	y->n--;
}
//x的第i个关键字转移到左子结点
void Btree::Shift_Left(Node* x, int i, Node* y, Node* z)//i-1才为索引
{
	y->n++;
	y->key[y->n - 1] = x->key[i - 1];
	x->key[i - 1] = z->key[0];
	z->n--;
	int j = 0;
	while (j < z->n)
	{
		z->key[j] = z->key[j + 1];
		j++;
	}
	if (!z->isleaf)
	{
		y->C[y->n] = z->C[0];
		j = 0;
		while (j <= z->n)
		{
			z->C[j] = z->C[j + 1];
			j++;
		}
	}
}
void Btree::Merge(Node* x, int i, Node* y, Node* z)//i-1才为C++索引
{
	y->n = 2 * t - 1;
	for (int j = t; j < 2 * t - 1; j++)
		y->key[j] = z->key[j - t];
	y->key[t - 1] = x->key[i - 1];
	if (!y->isleaf)
	{
		for (int j = t; j <= 2 * t - 1; j++)
			y->C[j] = z->C[j - t];
	}
	for (int j = i; j < x->n; j++)
		x->key[j - 1] = x->key[j];
	for (int j = i; j < x->n; j++)
		x->C[j] = x->C[j + 1];
	x->n--;
	delete z;
}
void Btree::DeleteNon(Node* x, int k)
{
	Node* y = nullptr;
	Node* z = nullptr;
	int i = 0;
	if (x->isleaf)                            //Case1
	{
		while (i < x->n&&k>x->key[i])
		{
			i++;
		}
		if (k == x->key[i])
		{
			x->n--;
			for (int j = i; j < x->n; j++)
			{
				x->key[j] = x->key[j + 1];
			}
		}
		else cout << "DF!!!\n";
	}
	else
	{
		while (i<x->n&&k>x->key[i])
		{
			i++;
		}
		y = x->C[i];
		if (i < x->n)
			z = x->C[i + 1];
		if (k == x->key[i])                      //Case2
			if (y->n > t - 1)                    //Case2 a
			{
				int k0 = Predecessor(y);
				DeleteNon(y, k0);
				x->key[i] = k0;
			}
			else if (z->n > t - 1)               //Case2 b
			{
				int k0 = Successor(z);
				DeleteNon(z, k0);
				x->key[i] = k0;
			}
			else                                  //Case2 c
			{
				Merge(x, i + 1, y, z);
				DeleteNon(y, k);
			}
		else                                      //Case3
		{
			Node* p = nullptr;
			if (i > 0)//最左端的情况,无左兄弟结点
				p = x->C[i - 1];//左兄弟结点,y为目标结点,z为右兄弟结点
			if (y->n == t - 1)
			{
				if (i > 0 && p->n > t - 1)
					Shift_Right(x, i, p, y);//i为第几个,不为索引        Case3 a
				else if (i<x->n&&z->n>t - 1)
					Shift_Left(x, i + 1, y, z);
				else if (i > 0)
				{
					Merge(x, i, p, y);            //Case3 b
					y = p;
				}
				else
					Merge(x, i + 1, y, z);
			}
			DeleteNon(y, k);
		}
	}
}
void Btree::Delete(int k)
{
	Node* r = root;
	if (r->n == 1)
	{
		Node* y = r->C[0];
		Node* z = r->C[1];
		if (y->n == t - 1 && z->n == t - 1)
		{
			Merge(r, 1, y, z);
			root = y;
			delete r;
			DeleteNon(y, k);
		}
		else
			DeleteNon(r, k);
	}
	else
		DeleteNon(r, k);
}


完。

猜你喜欢

转载自blog.csdn.net/qq_40510553/article/details/80239066