我的错误B树递归实现
第一篇总的介绍.
第二篇插入的介绍.
第三篇删除的介绍.
花了很久的时间,最后还是没有达到我希望的功能,有点遗憾,但是在这个过程中我也学会了一些东西,首先要明白程序设计需求,再考虑设计模式,明确函数功能划分、接口设计,画出我实现的流程图,将我的实现算法能清晰表达出来再动手写伪代码,再手写具体代码自己纸上运行演算,最后再上机调试。由于我时间不是很多了,所以还有一些问题我就没有解决,留待非递归实现解决。之前各个部分的思路,具体实现都在我的同系列文章中了,就不在这里赘述。
具体代码:
#include<iostream>
typedef int KeyType;
const int T=3;
typedef struct Btreenode{
KeyType key[2*T-1]={0}; //关键字数组
bool leaf=true; //默认叶子结点为真
int n=0; //结点个数
struct Btreenode* son[2*T]={nullptr}; //子结点数组
struct Btreenode* father=nullptr; //父指针
}Btreenode;
typedef Btreenode* B_tree;
using namespace std;
B_tree Insert(B_tree,KeyType); //插入函数
B_tree Delete_Key(B_tree,KeyType); //删除关键字
B_tree Search(B_tree,KeyType); //搜索关键字返回结点地址
int KeyReplace(B_tree,KeyType); //在子结点中找一个关键字代替待删除的关键字
int Find_position(B_tree,KeyType); //查找关键字所在位置
B_tree Split(B_tree); //分裂结点函数,返回新生成的结点地址
void Sortkey(B_tree,KeyType); //将一个新关键字插入结点并排序
void Sortson(B_tree,B_tree); //将一个新儿子插入父结点的儿子数组并排序
void Cat(B_tree,B_tree); //将一个结点的某个位置开始剪切给另外一个结点
void Cat(B_tree,B_tree,KeyType); //合并结点时用的剪切函数
void AdjustNode(B_tree,int); //将某个位置后面的数据前进一个位置
int MergeNode(B_tree,int); //将后一个结点剪切至第一个结点
int TransferKey(B_tree,int); /*将一个相邻的兄弟结点的关键字转移到父结点,
再将父结点的一个关键字转移到该结点*/
int main(void){
B_tree temp=nullptr,root=new Btreenode;
KeyType x;
int i=0;
while(cin>>x){
Insert(root,x);
if(root->father) root=root->father;
}
cin.clear();
cin.ignore();
cout<<endl;
cout<<"Please input the key you want to delete."<<endl;
cin>>x;
Delete_Key(root,x);
cout<<"Please input the key you want to search."<<endl;
cin>>x;
temp=Search(root,x);
for(;i<temp->n;i++) if(temp)cout<<temp->key[i]<<endl;
return 0;
}
B_tree Insert(B_tree root,KeyType newkey){
int flag=0;
B_tree newson=nullptr; //分裂结点后会产生新儿子
int position=Find_position(root,newkey);
if(root->n==2*T-1){ //满结点
KeyType temp=root->key[T-1];
newson=Split(root); //newson是继承了满结点的后半部分的新儿子结点
if(newkey<temp) flag=1;
else flag=2;
}else{
if(root->leaf==false) flag=3; //内部结点
else Sortkey(root,newkey); //叶子结点
}
if(flag==1) return Insert(root,newkey); //在分裂后的当前结点中插入
else if(flag==2) return Insert(newson,newkey); //在分裂后产生的新儿子中进行插入
else if(flag==3) return Insert(root->son[position],newkey); //当前结点为内部结点,递归查找合适的叶结点进行插入
else return root; //已经将关键字插入到叶结点中了
}
B_tree Search(B_tree root,KeyType x){
int position=Find_position(root,x);
if(root->key[position]==x) return root;
else{
if(root->son[position])return Search(root->son[position],x);
else return nullptr;
}
}
B_tree Split(B_tree p){
B_tree newson=new Btreenode;
KeyType new_father_key=p->key[T-1];
Cat(p,newson);
if(p->father){ //p有父结点
Sortkey(p->father,new_father_key);
Sortson(p->father,newson);
}else{ //没有父结点,说明待分裂结点为根结点
B_tree newfather=new Btreenode;
p->father=newfather;
newson->father=newfather;
newfather->son[0]=p;
newfather->key[0]=new_father_key;
newfather->n++;
newfather->son[1]=newson; //因为newson继承了原来结点的右半边比原来结点大
newfather->leaf=false;
}
return newson;
}
void Sortkey(B_tree p,KeyType newkey){
KeyType temp[2*T-1]={0};
int i=0,j=0,flag=1; //flag=1代表新关键字未插入
for(;i<p->n;i++,j++){
if(flag&&p->key[i]>newkey){
temp[j]=newkey;
temp[++j]=p->key[i];
flag=0;
}else if(p->key[i]==newkey){
cout<<"The key you have input."<<endl;
return;
}else temp[j]=p->key[i];
}
if(flag) temp[j]=newkey;
for(i=0;i<=j;i++) p->key[i]=temp[i];
p->n++;
}
void Sortson(B_tree father,B_tree newson){
B_tree temp[2*T]={nullptr};
int i=0,j=0,flag=1; //flag=1代表新儿子未插入父结点的儿子数组
for(;i<father->n;i++,j++){
if(flag&&father->son[i]->key[0]>newson->key[0]){
temp[j]=newson;
temp[++j]=father->son[i];
flag=0;
}else temp[j]=father->son[i];
}
if(flag) temp[j]=newson;
for(i=0;i<2*T&&temp[i];i++) father->son[i]=temp[i];
}
void Cat(B_tree first,B_tree second){ //begin是第一个结点传关键字给第二个结点的起始位置
int i=T,j=0;
first->key[T-1]=0; //在分裂结点时因为这个关键字已经被传给了父结点
for(;i<2*T-1;i++,j++){
second->key[j]=first->key[i];
first->key[i]=0;
second->son[j]=first->son[i];
first->son[i]=nullptr;
}
second->son[j]=first->son[i]; //因为儿子结点比关键字多一
first->son[i]=nullptr;
second->n=first->n=T-1;
second->leaf=first->leaf;
second->father=first->father;
}
void Cat(B_tree first,B_tree second,KeyType x){
int i=first->n,j=0;
first->key[i++]=x;
for(;i<2*T-1;i++,j++){
first->key[i]=second->key[j];
first->son[i]=second->son[j];
first->n++;
}
first->son[i]=second->son[j]; //儿子比关键字多一
delete(second);
}
void AdjustNode(B_tree p,int position){
for(;position<p->n-1;position++){
p->key[position]=p->key[position+1];
p->son[position+1]=p->son[position+2];
}
p->key[position]=0;
p->son[position+1]=nullptr;
p->n--;
}
int MergeNode(B_tree father,int position){
B_tree left_brother=nullptr,right_brother=nullptr;
int flag=0;
if(position>0) left_brother=father->son[position-1];
if(position<father->n) right_brother=father->son[position+1];
if(left_brother){ //有左兄弟与左兄弟合并
Cat(left_brother,father->son[position],father->key[position]);
AdjustNode(father,position);
flag=3;
}else if(right_brother){
Cat(right_brother,father->son[position],father->key[position]);
AdjustNode(father,position);
flag=4;
}
return flag;
}
int TransferKey(B_tree father,int position){
B_tree left_brother=nullptr,right_brother=nullptr;
int flag=0;
if(position>0) left_brother=father->son[position-1];
if(position<father->n) right_brother=father->son[position+1];
if(left_brother&&left_brother->n>T-1){ //左兄弟有至少T个关键字
Sortkey(father->son[position],father->key[position-1]);
Sortson(father->son[position],left_brother->son[left_brother->n]);
father->key[position-1]=left_brother->key[left_brother->n-1];
left_brother->key[left_brother->n-1]=0;
left_brother->son[left_brother->n]=nullptr;
flag=6;
}else if(right_brother&&right_brother->n>T-1){//右兄弟有至少T个关键字
Sortkey(father->son[position],father->key[position+1]);
Sortson(father->son[position],right_brother->son[0]);
father->key[position+1]=right_brother->key[0];
AdjustNode(right_brother,0);
flag=7;
}
return flag;
}
int KeyReplace(B_tree p,int position){
B_tree last_son=p->son[position],next_son=p->son[position+1];
int flag=0; //如果结束时返回的flag=0则说明未替换
if(last_son&&last_son->n>T-1){ //如果前一个儿子至少有T个关键字
p->key[position]=last_son->key[last_son->n-1];
flag=1; //说明用其前一个儿子的关键字进行替换
}else if(next_son&&next_son->n>T-1){
p->key[position]=next_son->key[0];
flag=2; //说明用其后一个儿子进行替换
}
return flag;
}
int Find_position(B_tree p,KeyType x){
int i=0,position=0,flag=1; //flag=1说明还未定位到关键字位置
for(;i<p->n;i++){
if(flag&&(x<p->key[i]||x==p->key[i])){
position=i;
flag=0; //说明已经定位到其位置
}
}
if(flag) position=i; //说明其比这个结点中的关键字大
return position;
}
B_tree Delete_Key(B_tree root,KeyType x){
int position=Find_position(root,x),flag=0; //flag是标志变量用来
B_tree left_brother=nullptr,right_brother=nullptr;
if(position>0) left_brother=root->son[position-1];
if(position<root->n) right_brother=root->son[position+1];
if(root->key[position]==x){ //待删除关键字在当前结点中
if(root->leaf) AdjustNode(root,position); //当前结点为叶结点
else{ //当前结点为内部结点
flag=KeyReplace(root,position); //若待删除关键字的相邻结点有至少T个关键字就进行关键字替换
if(flag==0) flag=MergeNode(root,position); //合并结点
}
}else{ //待删除关键字不在当前结点
if(root->son[position]->n>T-1) flag=5; //待降落的结点有至少T个关键字
else{ //待降落的结点只有T-1个关键字
flag=TransferKey(root,position); //待降落结点的兄弟结点有至少T个关键字就进行关键字转移
if(flag==0){ //说明其兄弟结点都只有T-1个关键字,进行关键字合并
flag=MergeNode(root,position);
}
}
}
if(root->n==0){ //当前结点为根结点合并后无关键字,则合并结点成为新根结点
B_tree temp=root;
root=root->son[0];
delete(temp);
}
if(flag==0) return root;
/*①*/else if(flag==1) return Delete_Key(root->son[position],root->son[position]->key[root->son[position]->n-1]);
/*②*/else if(flag==2) return Delete_Key(root->son[position+1],root->son[position+1]->key[0]);
/*③*/else if(flag==3) return Delete_Key(root->son[position-1],x);
/*④*/else if(flag==4) return Delete_Key(root->son[position+1],x);
/*⑤*/else return Delete_Key(root->son[position],x);
}