数据结构学习——浅谈B树的一些相关总结

本文介绍了B-树,它是平衡的多叉搜索树。其优势在于节点信息多可降低树高度、减少IO次数,如MySQL数据库索引底层就用此结构。还阐述了B树规则,给出三阶模拟实现,包括查找和插入元素的方法及代码示例,最后提及了B树的性能分析。

B-树 —— 平衡的多叉搜索树。

1.优势

  1. 如果一个节点中保存的信息多一些,那么树的高度就会降低;多个孩子节点指针意味着降低了树的高度(提高查找效率)
  2. 数据节点多一些,相应的也会降低IO次数。我们应该知道的是Mysql这些数据库的索引的底层实现部分就是用B-树这种结构来实现的。

2.规则

一棵m阶B树(balanced tree of order m)是一棵平衡的m路搜索树。它或者是空树,或者是满足下列性质的树:
在这里插入图片描述

3.三阶模拟实现

M=3(三叉树)

1.Find() :找待插入元素的位置;
用当前元素与待插入节点中的元素依次进行比较;

  1. ‘==’ : return;
  2. ‘<’ : 在其第i个孩子中找;
  3. ‘>’: 继续向后比较: 1.后边有元素,继续比 2.后边没有元素,与当前元素的i+1个孩子中找

2.Insert() :插入元素:
为了简单起见,假设M = 3. 即三叉树,每个节点中存储两个数据,两个数据可以将区间分割成三个部分,因此节点应该有三个孩子,为了后续实现简单期间,节点的结构如下:
在这里插入图片描述
注意:孩子永远比数据多一个。

while (1){
1.满足条件按照直接插入排序思想直接插入

2.不满足条件,分裂
.1找到当前节点元素的中间位置;
.2申请一个新的节点
.3中间节点元素右边的元素以及其对应的孩子搬移到新节点中;
.4将中间元素想其双亲节点中继续插入
}

在这里插入图片描述

.三叉树代码示例:

//节点
template<class T, size_t M = 3>
struct BTreeNode
{
	BTreeNode()
	: _size(0)
	, _pParent(nullptr)
	{
		for (size_t i = 0; i < M + 1; ++i)
			_child[i] = nullptr;
	}

	// 存放元素的空间
	T _array[M];
	BTreeNode<T, M>* _child[M + 1];
	size_t _size;  // 当前节点中有效元素的个数
	BTreeNode<T, M>* _pParent;
};
template<class T, size_t M = 3>
class BTree
{
	typedef BTreeNode<T, M> Node;
public:
	BTree()
		: _pRoot(nullptr)
	{}

	pair<Node*, int> Find(const T& data)
	{
		Node* pCur = _pRoot;
		Node* pParent = nullptr;
		while (pCur)
		{
			size_t index = 0;
			while (index < pCur->_size)
			{
				if (pCur->_array[index] == data)
					return make_pair(pCur, index);
				else if (data < pCur->_array[index])
				{
					break;
				}
				else
				{
					index++;
				}
			}

			pParent = pCur;
			pCur = pCur->_child[index];
		}

		return make_pair(pParent, -1);
	}

	bool Insert(const T& data)
	{
		if (nullptr == _pRoot)
		{
			_pRoot = new Node;
			_pRoot->_array[0] = data;
			_pRoot->_size++;
			return true;
		}

		// 1. 找待插入元素在B-树中的位置
		pair<Node*, int> ret = Find(data);
		if (-1 != ret.second)
			return false;

		// 2. 插入元素
		Node* pCur = ret.first;

		T key = data;
		Node* pSub = nullptr;
		while (true)
		{
			// 将data插入pCur
			InsertKey(pCur, key, pSub);

			// 当前pCur节点已经违反B树的性质
			if (pCur->_size != M)
				return true;

			//必须对当前节点进行分裂
			// 找当前节点元素的中间位置
			int mid = (M >> 1);

			Node* pNewNode = new Node;
			size_t count = 0;
			// 将当前节点中间位置以后的元素搬移到新节点中
			int index = mid + 1;
			for (; index < pCur->_size; ++index)
			{
				// 搬移元素
				pNewNode->_array[count] = pCur->_array[index];
				
				// 搬移元素对应的孩子
				pNewNode->_child[count] = pCur->_child[index];

				// 更新孩子的双亲
				if (pCur->_child[index])
					pCur->_child[index]->_pParent = pNewNode;
				
				count++;
			}

			// 孩子要多搬移一个
			pNewNode->_child[count] = pCur->_child[index];
			if (pCur->_child[index])
				pCur->_child[index]->_pParent = pNewNode;

			// 更新当前节点中剩余元素的个数
			pCur->_size = pCur->_size - count - 1;
			pNewNode->_size = count;

			// 将中间元素和分裂出的节点向双亲节点中继续进行插入
			// 如果待分裂的节点刚好是根节点
			if (nullptr == pCur->_pParent)
			{
				_pRoot = new Node;
				_pRoot->_array[0] = pCur->_array[mid];
				_pRoot->_size = 1;
				_pRoot->_child[0] = pCur;
				_pRoot->_child[1] = pNewNode;
				pCur->_pParent = _pRoot;
				pNewNode->_pParent = _pRoot;
				return true;
			}
			else
			{
				key = pCur->_array[mid];
				pSub = pNewNode;
				pCur = pCur->_pParent;
			}
		}
	}

	void InOrder()
	{
		_InOrder(_pRoot);
	}

private:
	// 借助插入排序的思想
	void InsertKey(Node* pCur, const T& key, Node* pSub)
	{
		int end = pCur->_size - 1;
		while (end >= 0 && key < pCur->_array[end])
		{
			// 搬移元素
			pCur->_array[end+1] = pCur->_array[end];
			
			// 搬移当前元素对应右侧的孩子
			pCur->_child[end+2] = pCur->_child[end+1];
			end--;
		}

		pCur->_array[end+1] = key;
		pCur->_child[end+2] = pSub;

		// 如果psub不为空,说明pSub一定为分裂出的新节点
		// 如果psub为空,说明是在第一插入元素
		if (pSub)
			pSub->_pParent = pCur;

		pCur->_size++;
	}

	void _InOrder(Node* pRoot)
	{
		if (nullptr == pRoot)
			return;

		for (size_t i = 0; i < pRoot->_size; ++i)
		{
			_InOrder(pRoot->_child[i]);
			cout << pRoot->_array[i] << " ";
		}

		_InOrder(pRoot->_child[pRoot->_size]);
	}
private:
	Node* _pRoot;
};


4.B树的性能分析

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拥抱@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值