参考了《数据结构(c++语言版)》(清华大学 邓俊辉著)中B树的插入算法,简化了少许
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
struct Node{
vector<int> key;
vector<Node*> child;
Node *parent;
Node(){
parent=NULL;
child.push_back(NULL); //构造新节点时,左孩子为NULL
}
};
class BTree{
public:
int order;
Node *root;
Node *hot; //hot指向B树搜索某键时去到最深的节点位置(叶子节点/根节点)
BTree(int od=3){ //默认构造3阶B树,即2,3树
order=od;
root=new Node;
}
Node *search(int e);
bool insert(int e);
bool remove(int e);
void solveOverflow(Node *node);
void solveUnderflow(Node *node);
void printTree();
};
Node* BTree::search(int e){ //B树搜索
Node *tempnode=root; //tempnode为在此节点搜索目标键
while(tempnode){
int posi=0;
hot=tempnode;
while(posi<tempnode->key.size()){
if(e==tempnode->key[posi]) return tempnode; //搜索成功返回此节点
else if(e<tempnode->key[posi]) break; //找到转入对应子树合适位置
posi++;
}
tempnode=tempnode->child[posi]; //搜索失败转入对应子树搜索
}
return NULL; //B树无此键,返回NULL
}
bool BTree::insert(int e){
Node *n=search(e);
if(n) return false; //树中已有此键,返回false
int posi=0; //树中没有此键,在hot节点(搜索目标键时抵达的最深节点,即叶子节点/根节点)找到插入键的合适位置
while(posi<hot->key.size()){
if(e<hot->key[posi]){ //一直到hot节点某键大于目标键
break;
}
posi++;
}
hot->key.insert(hot->key.begin()+posi,e); //在hot节点插入目标键
hot->child.insert(hot->child.begin()+posi+1,NULL); //hot节点中目标键右孩子为NULL
solveOverflow(hot); //检查是否需要分裂
return true;
}
void BTree::solveOverflow(Node *node){
if(node->key.size()<order){ //如果节点键少于m个则不分裂
return;
}
int riseposi=order/2; //riseposi为需要上升的键
Node *newnode=new Node; //分裂出的右边的新的节点
newnode->child.erase(newnode->child.begin()); //删去构造新节点时,最左孩子的指向NULL
for(int i=riseposi+1;i<node->key.size();i++){ //把原节点riseposi右边的键和孩子给新节点
newnode->key.push_back(node->key[riseposi+1]);
node->key.erase(node->key.begin()+riseposi+1);
newnode->child.push_back(node->child[riseposi+1]);
node->child.erase(node->child.begin()+riseposi+1);
}
newnode->child.push_back(node->child[riseposi+1]); //把原节点最右边的孩子给新节点
node->child.erase(node->child.begin()+riseposi+1);
if(newnode->child[0]!=NULL){ //新节点(原节点)不是是叶子节点时,让孩子父亲指向新节点(是叶子节点时孩子为NULL不用)
for(Node* child:newnode->child){
child->parent=newnode;
}
}
Node *p=node->parent;
if(!p){ //原节点是根节点(没有父节点)时,创建新的根节点,root重新指向新根节点,新根节点左孩子为原节点
root=p=new Node();
p->child[0]=node;
node->parent=p;
}
int posiins=0; //在原节点的父节点搜索合适位置插入上升的键
while(posiins<p->child.size()){
if(p->child[posiins]==node) break;
posiins++;
}
p->key.insert(p->key.begin()+posiins,node->key.back()); //父节点中插入上升的键
node->key.pop_back(); //原节点删去上升的键
p->child.insert(p->child.begin()+posiins+1,newnode); //父节点中上升的键的右孩子指向新节点
newnode->parent=p; //新节点父亲指向父节点
solveOverflow(p);
}
void BTree::printTree(){ //广搜
queue<Node*> que;
que.push(root);
while(!que.empty()){
Node *topnode = que.front();
que.pop();
for(int i=0;i<topnode->key.size();i++){
std::cout<<topnode->key[i]<<" \n"[i==topnode->key.size()-1];
}
if(topnode->child[0]!=NULL){
for(Node *node:topnode->child){
que.push(node);
}
}
}
}
int main(){
BTree btr;
btr.insert(20);
btr.insert(40);
btr.insert(30);
btr.insert(50);
btr.insert(25);
btr.insert(60);
btr.insert(10);
btr.printTree();
return 0;
}