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;
- }
中序遍历结果为