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树的插入
例如插入20 30 10 ,画图分析如下
源代码
#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;
}
中序遍历结果为