【数据结构】B树(B-Tree)

B树
1970年,R.Bayer和E.mccreight提出了一种适合外查找的树,它是一种平衡的多叉树,称为B树。(有些地方写的是B-树,注意不要误读
成”B减树”)
一棵M阶(M>2)的B树,是一棵平衡的M路平衡搜索树,可以是空树或者满足一下性质:
1. 根节点至少有两个孩子
2. 每个非根节点有[ ,M]个孩子
3. 每个非根节点有[ -1,M-1]个关键字,并且以升序排列
4. key[i]和key[i+1]之间的孩子节点的值介于key[i]、key[i+1]之间
5. 所有的叶子节点都在同一层

ps: 是向上取整

B树是一种高度平衡树

这里以M=3为例进行解释

例如一个树中有数组int arr[]={3,4,10,15,16,20,30,35,36,40,45,46,50,76,77};那么它的结构如下图

《【数据结构】B树(B-Tree)》

B树的插入

例如插入20 30 10 ,画图分析如下

《【数据结构】B树(B-Tree)》


源代码

#pragma  once
#include <vector>
#include <iostream>
using namespace std;
template<class K,int M>
struct BTreeNode
{
	K _keys[M];//关键字数组,多一个便于分解
	BTreeNode<K,M>* _subs[M+1];//连接子树的指针数组
	BTreeNode<K,M>* _parent;
	int size;//关键字个数

	BTreeNode()
		:size(0)
		,_parent(NULL)
	{
		size_t i=0;
		for (i=0;i<M;++i)
		{
			_keys[i]=K();
			_subs[i]=NULL;
		}
		_subs[M]=NULL;
	}

};
template<class K,int M>
class BTree
{
	typedef BTreeNode<K,M> Node;
public:
	BTree()
		:_root(NULL)
	{}
 pair<Node*,int> Find(const K& key)
 {
	 Node* cur=_root;
	 Node* parent=NULL;
	 while(cur)
	 {
		 int i=0;
		 while(i<cur->size)
		 {
			 if(cur->_keys[i]<key)
			 {
			 ++i;
			 }
			 else if (cur->_keys[i]>key)
			 {
				 break;
			 }
			 else//找到关键字
			 {
               return pair<Node*,int>(cur,i);
			 }
			 
		 }
			 parent=cur;
			 cur=cur->_subs[i];
	 
	 }
	 return pair<Node*,int>(parent,-1);//没有找到关键字返回-1;
 }
 bool Insert(const K& key)
 {
	 if(_root==NULL)//空树的插入
	 {
		 _root=new Node;
		 
		 _root->_keys[0]=key;
		 _root->size=1;
		 return true;
	 }
	 pair<Node*,int> ret=Find(key);
	 if(ret.second!=-1)//如果没有找到则插入,找到则不插入
		 return false;

     Node* cur=ret.first;
	 K newkey=key;
	 Node* sub=NULL;
	 
	 while(1)
	 {
		 InsertKey(cur,newkey,sub);
		 if(cur->size<M)//如果插入后没有满,则直接返回
			 return true;

		 size_t mid=cur->size/2;//插入后导致M满了,进行分裂
		 Node* tmp=new Node;
		 int j=0;
		 for(int i=mid+1;i<cur->size;++i)//拷贝key及孩子,连续分裂
		 {
			 tmp->_keys[j]=cur->_keys[i];
			 if (cur->_subs[i])
			 {
				 tmp->_subs[j]=cur->_subs[i];
				 tmp->_subs[j+1]=sub;
				 cur->_subs[i]=NULL;

				 tmp->_subs[j]->_parent=tmp;
				 tmp->_subs[j+1]->_parent=tmp;
			 }
			  tmp->size++;
			  cur->_keys[i]=K();
			  cur->size--;
			  j++;
		 }

		 if(cur->_parent==NULL)//分裂到根节点
		 {
		 _root=new Node;
		 _root->_keys[0]=cur->_keys[mid];
		 
		 _root->_subs[0]=cur;
		 _root->_subs[1]=tmp;
         _root->size++;

		 cur->_keys[mid]=K();
		 cur->size--;

		 cur->_parent=_root;
		 tmp->_parent=_root;

		 return true;
		 }
		 //没有分裂到根节点
		 newkey=cur->_keys[mid];
		 cur->_keys[mid]=K();
		 cur->size--;
         sub=tmp;
		 cur=cur->_parent;//上移
		
	 }

	 return true;
 }
 void Inorder()
 {
	 _Inorder(_root);
	 cout<<endl;
 }
protected:
	void InsertKey(Node* node,const K& key,Node* sub)
	{
		int i=node->size-1;
		while (i>=0)
		{
			if(node->_keys[i]>key)
			{
				node->_keys[i+1]=node->_keys[i];
				node->_subs[i+2]=node->_subs[i+1];
			    --i;
			}
			else
			{
				
				break;
			}
			
		}
		node->_keys[i+1]= key;
		node->_subs[i+2]=sub;
		if(sub)
		sub->_parent=node;
		node->size++;
	}
	void _Inorder(Node* root)//打印完一个子树再递归下一步进行打印
	{
		if(root==NULL)
			return;
	    _Inorder(root->_subs[0]);
		for (int i=0;i<root->size;i++)
		{
          // _Inorder(root->_subs[i]);
           cout<<root->_keys[i]<<" ";
		}
		
		for(int i=1;i<M;++i)
		{
			_Inorder(root->_subs[i]);
		}
	}
private:
	Node* _root;
};
void testBTree()
{

	BTree<int,3> bt;
	int arr[]={53, 75, 139, 49, 145, 36, 101};
	for(int i=0;i<sizeof(arr)/sizeof(arr[0]);++i)
	{
		bt.Insert(arr[i]);
	}
	bt.Inorder();
}

#include "BTree.h"
#include <cstdlib>
int main()
{
	testBTree();

	system("pause");
	return 0;
}

中序遍历结果为

《【数据结构】B树(B-Tree)》

    原文作者:B树
    原文地址: https://blog.csdn.net/shangguan_1234/article/details/53140564
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞