T:B数的表示及其基本操作的实现(C++)

习题内容:

1.掌握B树的存贮结构。

2.实现B树中关键字值的插入及删除操作。

B树的定义:

B树也称B-树,它是一颗多路平衡查找树。我们描述一颗B树时需要指定它的阶数,阶数表示了一个结点最多有多少个孩子结点,一般用字母M表示阶数。当M取2时,就是我们常见的二叉搜索树。

一颗M阶的B树定义如下:

1)每个结点最多有M-1个关键字。

2)根结点最少可以只有1个关键字。

3)非根结点至少有Math.ceil(M / 2)-1个关键字。

4)每个结点中的关键字都按照从小到大的顺序排列,每个关键字的左子树中的所有关键字都小于它,而右子树中的所有关键字都大于它。

扫描二维码关注公众号,回复: 4631673 查看本文章

5)所有叶子结点都位于同一层,或者说根结点到每个叶子结点的长度都相同。

代码实现:

/*测试环境:VS2017*/

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;

typedef struct _BTreeNode
{
	int key_count;
	int* key;
	bool leaf;
	_BTreeNode** child;
}BTreeNode, *PBTreeNode;

class BTree
{
private:
	PBTreeNode root;
	int t;//B树的度,树的阶数为2t***m=2t,t=m/2

public:
	BTree(int m):root(NULL), t(m){}//构造
	~BTree(){DeleteTree(root);delete root;}//析构

	//基本操作:插入,删除,打印,查询
	void Insert(int key);
	void Delete(int key) { DeleteNonHalf(root, key); }
	void Display() { Print(root); }
	bool Search(int key);
private:
	PBTreeNode SearchBT(PBTreeNode pNode, int key);
	PBTreeNode AllocateNode();//划分节点,初始化
	PBTreeNode UnionChild(PBTreeNode pParent, PBTreeNode pCLeft, PBTreeNode pCRight, int index);//结合兄弟节点
	int Max(PBTreeNode pNode);
	int Min(PBTreeNode pNode);
	void DeleteNonHalf(PBTreeNode pNode, int key);//删除不足的节点
	void InsertNonfull(PBTreeNode pNode, int key);//插入未满的节点
	void SplitChild(PBTreeNode pParent, int index, PBTreeNode pChild);//划分子节点
	void DeallocateNode(PBTreeNode pNode);//解除划分
	void DeleteTree(PBTreeNode pNode);//删除树
	void Print(PBTreeNode pNode);//打印树
};

void BTree::Insert(int key)
{
	PBTreeNode r = root;
	if (r == NULL)
	{
		r = AllocateNode();
		r->leaf = true;
		r->key_count = 0;
		root = r;
	}

	if (r != NULL && r->key_count == (2 * t - 1))
	{
		PBTreeNode s = AllocateNode();
		root = s;
		s->leaf = false;
		s->key_count = 0;
		s->child[1] = r;
		SplitChild(s, 1, r);
		InsertNonfull(s, key);
	}
	else
	{
		InsertNonfull(r, key);
	}
	cout << "成功插入关键字:" << key << endl;
}

bool BTree::Search(int key)
{
	if (SearchBT(root, key))
		return false; 
	else 
		return true; 
}

PBTreeNode BTree::AllocateNode()
{
	PBTreeNode pTemp = new BTreeNode;
	pTemp->key = new int[2 * t];
	pTemp->child = new PBTreeNode[2 * t + 1];

	//初始化
	for (int i = 0; i < 2 * t; i++)
	{
		pTemp->key[i] = 0;
		pTemp->child[i] = NULL;
	}
	pTemp->child[2 * t] = NULL;

	return pTemp;
}

PBTreeNode BTree::SearchBT(PBTreeNode pNode, int key)
{
	int i = 1;
	while (i <= pNode->key_count && key > pNode->key[i])
		i++;
	
	if (i < pNode->key_count && key == pNode->key[i])
		return pNode->child[i];

	if (pNode->leaf)
		return NULL;
	else
		return SearchBT(pNode->child[i], key);
}

PBTreeNode BTree::UnionChild(PBTreeNode pParent, PBTreeNode pCLeft, PBTreeNode pCRight, int index)
{
	for (int i = 1; i < t; i++)
		pCLeft->key[t + i] = pCRight->key[i];
	pCLeft->key[t] = pParent->key[index];

	for (int i = 1; i <= t; i++)
		pCLeft->child[t + i] = pCRight->child[i];
	pCLeft->key_count = 2 * t - 1;

	for (int i = index; i < pParent->key_count; i++)
		pParent->key[i] = pParent->key[i + 1];

	for (int i = index + 1; i <= pParent->key_count; i++)
		pParent->child[i] = pParent->child[i + 1];
	pParent->key_count--;

	DeallocateNode(pCRight);

	if (pParent->key_count == 0)
	{
		DeallocateNode(root);
		root = pCLeft;
	}

	return pCLeft;
}

int BTree::Max(PBTreeNode pNode)
{
	while (!pNode->leaf)
	{
		pNode = pNode->child[pNode->key_count + 1];
	}

	return pNode->key[pNode->key_count];
}

int BTree::Min(PBTreeNode pNode)
{
	while (!pNode->leaf)
	{
		pNode = pNode->child[1];
	}

	return pNode->key[1];
}

void BTree::DeleteNonHalf(PBTreeNode pNode, int key)
{
	int i = 1;

	while (i <= pNode->key_count && key > pNode->key[i])
		i++;

	if (pNode->leaf)
	{
		if (i <= pNode->key_count && key == pNode->key[i])
		{
			for (int j = i; j < pNode->key_count; j++)
				pNode->key[j] = pNode->key[j + 1];
			pNode->key_count--;
			cout << "成功删除关键字:" << key << endl;
			return;
		}
		else
		{
			//cout << "未能找到关键字:" << key << endl;
			return;
		}
	}

	if (i <= pNode->key_count && key == pNode->key[i])
	{
		if (pNode->child[i]->key_count >= t)
		{
			key = Max(pNode->child[i]);
			pNode->key[i] = key;

			DeleteNonHalf(pNode->child[i], key);
		}
		else if (pNode->child[i + 1]->key_count >= t)
		{
			key = Min(pNode->child[i + 1]);
			pNode->key[i] = key;

			DeleteNonHalf(pNode->child[i + 1], key);
		}
		else
		{
			PBTreeNode pChild = UnionChild(pNode, pNode->child[i], pNode->child[i + 1], i);

			DeleteNonHalf(pChild, key);
		}
	}
	else if (pNode->child[i]->key_count == t - 1)
	{
		if (i > 1 && pNode->child[i - 1]->key_count >= t)
		{
			PBTreeNode pMidNode = pNode->child[i];
			PBTreeNode pPreNode = pNode->child[i - 1];

			int nPreNodeKeyCount = pPreNode->key_count;

			for (int j = pMidNode->key_count + 1; j > 1; j--)
				pMidNode->key[j] = pMidNode->key[j - 1];
			pMidNode->key[1] = pNode->key[i - 1];

			for (int j = pMidNode->key_count + 2; j > 1; j--)
				pMidNode->child[j] = pMidNode->child[j - 1];
			pMidNode->child[1] = pPreNode->child[nPreNodeKeyCount + 1];
			pMidNode->key_count++;

			pNode->key[i - 1] = pPreNode->key[nPreNodeKeyCount];

			pPreNode->key[nPreNodeKeyCount] = 0;
			pPreNode->key[nPreNodeKeyCount + 1] = NULL;
			pPreNode->key_count--;

			DeleteNonHalf(pMidNode, key);
		}
		else if (i <= pNode->key_count && pNode->child[i + 1]->key_count >= t)
		{
			PBTreeNode pMidNode = pNode->child[i];
			PBTreeNode pNextNode = pNode->child[i + 1];

			int nNextNodeKeyCount = pNextNode->key_count;
			int nMidNodeKeyCount = pMidNode->key_count;

			pMidNode->key[nMidNodeKeyCount + 1] = pNode->key[i];
			pMidNode->child[nMidNodeKeyCount + 2] = pNextNode->child[1];
			pMidNode->key_count++;

			pNode->key[i] = pNextNode->key[1];

			for (int j = 1; j < nNextNodeKeyCount; j++)
				pNextNode->key[j] = pNextNode->key[j + 1];
			for (int j = 1; j <= nNextNodeKeyCount; j++)
				pNextNode->child[j] = pNextNode->child[j + 1];
			pNextNode->key_count--;

			DeleteNonHalf(pMidNode, key);
		}
		else
		{
			if (i > pNode->key_count)//当i指向最后一个关键字时,合并时往前移动一步
				i--;

			PBTreeNode pChild = UnionChild(pNode, pNode->child[i], pNode->child[i + 1], i);

			DeleteNonHalf(pChild, key);
		}
	}

	DeleteNonHalf(pNode->child[i], key);
}

void BTree::DeallocateNode(PBTreeNode pNode)
{
	delete[] pNode->key;
	delete[] pNode->child;
	delete pNode;
}

void BTree::SplitChild(PBTreeNode pParent, int index, PBTreeNode pChild)
{
	PBTreeNode pChildEx = AllocateNode();
	pChildEx->leaf = pChild->leaf;
	pChildEx->key_count = t - 1;

	for (int j = 1; j < t; j++)
		pChildEx->key[j] = pChild->key[j + t];

	if (!pChild->leaf)
		for (int j = 1; j <= t; j++)
			pChildEx->child[j] = pChild->child[j + t];

	pChild->key_count = t - 1;

	for (int j = pParent->key_count + 1; j > index; j--)
		pParent->child[j + 1] = pParent->child[j];
	pParent->child[index + 1] = pChildEx;

	for (int j = pParent->key_count; j >= index; j--)
		pParent->key[j + 1] = pParent->key[j];
	pParent->key[index] = pChild->key[t];
	pParent->key_count++;
}

void BTree::InsertNonfull(PBTreeNode pNode, int key)
{
	int i = pNode->key_count;

	if (pNode->leaf)
	{
		while (i >= 1 && key < pNode->key[i])
		{
			pNode->key[i + 1] = pNode->key[i];
			i--;
		}

		pNode->key[i + 1] = key;
		pNode->key_count++;
	}
	else
	{
		while (i >= 1 && key < pNode->key[i])
			i--;
		i++;

		if (pNode->child[i]->key_count == (2*t - 1))
		{
			SplitChild(pNode, i, pNode->child[i]);

			if (key > pNode->key[i])
				i++;
		}

		InsertNonfull(pNode->child[i], key);
	}
}

void BTree::DeleteTree(PBTreeNode pNode)//最后的根元素没有被删除,但是根里的关键字数组和孩子指针数组已经删除
{
	if (pNode->leaf)
	{
		delete[] pNode->key;
		delete[] pNode->child;
	}
	else
	{
		for (int i = 1; i <= pNode->key_count + 1; i++)
		{
			DeleteTree(pNode->child[i]);
			delete pNode->child[i];
		}

		delete[] pNode->key;
		delete[] pNode->child;
	}
}

void BTree::Print(PBTreeNode pNode)
{
	if (pNode->leaf)
	{
		cout << "叶子节点数目及成员:" << pNode->key_count << "		";

		for (int i = 1; i <= pNode->key_count; i++)
		{
			cout << pNode->key[i] << "	";
		}
		cout << endl;
	}
	else
	{
		for (int i = 1; i <= pNode->key_count + 1; i++)
			Print(pNode->child[i]);

		cout << "内部节点数目及成员:" << pNode->key_count << "		";
		for (int i = 1; i <= pNode->key_count; i++)
		{
			cout << pNode->key[i] << "	";
		}
		cout << endl;
	}
}

int main()
{
	int num, n,data;
	cout << "请分别输入关键字的个数及要建立的B树的度数(中间用空格隔开):";
	cin >> num >> n;
	BTree BT(n);
	cout << "请输入" << num << "个建立B树所需的关键字(中间用空格隔开):";
	for (int i = num; i > 0; i--)
	{
		cin >> data;
		BT.Insert(data);
	}
	cout << "B树创建成功!" << endl;
	BT.Display();
	cout << "****************************************************************************" << endl;
	cin.ignore(1000, '\n');
	
	char s,ss[100];
	while (1)
	{
		cout << "请输入操作(I:插入,D:删除;以 ‘#’结束;多个数据间用空格隔开):" << endl;
		cin >> s;
		if (s == 'I')
		{
			while (cin >> ss && ss[0] != '#')
			{
				data = atoi(ss);
				/*if (BT.Search(data))
				{
					cout << "关键字" << data << "已存在!" << endl;
					continue;
				}*/
				BT.Insert(data);
			}
			BT.Display();
			cout << "****************************************************************************" << endl;
		}
		else if (s == 'D')
		{
			while (cin >> ss && ss[0] != '#')
			{
				data = atoi(ss);
				/*if (BT.Search(data)==false)
				{
					cout << "未能找到关键字:" << data << endl;
					continue;
				}*/
				BT.Delete(data);
				//cout << "成功删除关键字:" << data << endl;
			}
			BT.Display();
			cout << "****************************************************************************" << endl;
		}
		else
			cout << "输入错误!" << endl;
	}
	return 0;
}


/*
test data :

10 2
9 4 6 10 22 8 1 2 3 5 7 11 33 44 55 66 77 88 99

I 101 1001 111 1010 33 #
D 8 33 10 #

*/

猜你喜欢

转载自blog.csdn.net/Hodge_Z/article/details/85050598