B树详解

B树的引入

二叉搜索树、平衡二叉树、红黑树都是动态查找树,查找的时间复杂度和树的高度相关 O(log2n).

数据杂乱无章——线性搜索    O(n)
数字有序——二分查找  O(log2n)   最差退化成左单支树 O(n)
二叉搜索树/AVL/红黑树——O(log2n)

缺陷:数据量大时,树的高度太高,效率下降。




如何解决?

1.提高I/O的时间
2.降低树的高度——平衡多叉树。

B树定义

平衡的多叉树,称为B树(B-树)。


一棵M阶(M>2)的B树,是一个平衡的M路平衡搜索树,可以是空树或者满足以下性质:

1.根节点至少有两个孩子。
2.每个非根结点至少有M/2(上取整)个孩子,至多有M个孩子。
3.每个分根结点至少有M/2-1(上取整)个孩子,至多有M个孩子。
4.key[i]和key[i+1]之间的孩子结点的值介于key[i]、key[i+1]之间。
5.所有的叶子结点都在同一层。

图解

《B树详解》
《B树详解》

 《B树详解》《B树详解》

代码

#include <iostream>
using namespace std;

template<class K, size_t M>
struct BTreeNode
{
	typedef BTreeNode<K,M> Node;

	BTreeNode()
		:size(0)
		,_pParent(NULL)
	{}
	K _keys[M];  //关键字集合
	Node* _pSon[M+1];//孩子指针集合
	size_t size;
	Node* _pParent;
};

template<class K,size_t M>
class BTree
{
	typedef BTreeNode<K,M> Node;
public:
	BTree()
		:_pRoot(NULL)
	{}
bool Insert(const K&key)
{
	if (_pRoot == NULL)     //若树为空
	{
		_pRoot = new Node();
		_pRoot->_keys[0] = key;
		_pRoot->size++;
		_pRoot->_pSon[0] = NULL;
		_pRoot->_pSon[1] = NULL;
		return true;
	}

	//找插入位置
	pair<Node*,int> s = Find(key);
	if (s.second != -1)   //已经存在
		return false;

	Node* pCur = s.first;
	Node* pSub = NULL;
	K key1 = key;
	while(true)
	{
		_Insertkey(pCur,key1,pSub);  //插入key值  pSub是插入的结点的孩子,若是新插入的,则pSub的值赋为NULL
                                              //若是往上调整的,则需要调整孩子

		if (pCur->size <M) //无需调整
			return true;
		else
		{
			size_t mid = pCur->size/2;   //分裂取中 

			Node* pNew = new Node();
			size_t count = 0;
			size_t idx ;
			for( idx = mid+1;idx<pCur->size;)
			{
				pNew->_keys[count] = pCur->_keys[idx];
				pNew->_pSon[count++] = pCur->_pSon[idx++]; 
			}
			pNew->_pSon[count] = pCur->_pSon[idx];
			pCur->size = pCur->size - mid - 1;
			pNew->size = count;


			if (pCur == _pRoot)   //若原结点是根节点
			{
				_pRoot = new Node();
				_pRoot->_keys[0] = pCur->_keys[mid];
				_pRoot->_pSon[0] = pCur;
				pCur->_pParent = _pRoot;
				_pRoot->_pSon[1] = pNew;
				pNew->_pParent = _pRoot;
				_pRoot->size++;
				return true;
			} 

			pSub = pNew;    //更新孩子指针
			key1 = pCur->_keys[mid];   //更新要插入的值
			pCur = pCur->_pParent;  向上调整
		}
	}

}

pair<Node*,int> Find(const K& key)   //若查找失败,则返回 NULL和-1 
{
	Node * pCur = _pRoot;
	Node* pParent = NULL;
	size_t idx = 0;
	while (pCur)
	{
		idx = 0;
		while (idx < pCur->size)
		{
			if (pCur->_keys[idx]<key )
				idx++;
			else if (pCur->_keys[idx]>key)
				break;
			else
				return make_pair(pCur,idx);
		}
		if (idx == pCur->size&&pCur->_pSon[idx] == NULL)
		{
			return make_pair(pCur,-1);
		}
		else
		{
			pParent = pCur;
			pCur = pCur->_pSon[idx];
		}
	}
	return make_pair(pParent,-1);
}
void InOrder()
{
	_InOrder(_pRoot);
}
private:
	void _InOrder(Node* &pRoot)
	{
		if (pRoot== NULL)
			return;

		size_t idx;
		for(idx =0 ;idx<pRoot->size;++idx)
		{
			_InOrder(pRoot->_pSon[idx]);
			cout<<pRoot->_keys[idx]<<" ";
		}
		_InOrder(pRoot->_pSon[idx]);
	}
	void _Insertkey(Node* &pCur,const K& key,Node* pSub)
	{
		size_t end = pCur->size -1;
		while(end >= 0)
		{
			if (pCur->_keys[end] >key)    //后搬
			{

				pCur->_keys[end+1]= pCur->_keys[end];
				pCur->_pSon[end+2] = pCur->_pSon[end+1];
				--end;
			}
			else
			{
				pCur->_keys[end+1] = key;
				pCur->_pSon[end+2] = pSub;
				++pCur->size;
				return;
			}
		}
		pCur->_keys[0] = key;
		pCur->_pSon[0] = pSub;
		++pCur->size;
	}
private:
	Node* _pRoot;
};
    原文作者:B树
    原文地址: https://blog.csdn.net/wxx2222222/article/details/72853258
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注