C++ B树

来源:互联网 发布:小学英语听力软件 编辑:程序博客网 时间:2024/05/21 19:43

写了红黑树之后再写B树,可谓是轻松了不少,毕竟B树的分类情况比红黑树少太多。当然从效率上来说,我这个版本的B树实现效率肯定不是最高的,我是先删除移动后再做平衡,其实可以通过标识的方法在平衡里覆盖掉需要删除的点即可。当然写的时候为了思路更清晰,我并没有这样去写。还有个原因主要是,B树真的就是一种思路,就是通过这种结构算法,建立文件系统,从而大量数据搜索的时候,可以接近二分搜索的时间复杂度,优点就在于可以以片段的形式加载到内存,而且可以加载合适的大小,避免与硬盘多次IO交互的耗时。我写平衡的时候,还是尽量去避免了来回移动这个问题,不过还是有一定性能损失



#define M 4 //M个关键字  M+1阶 B树#define DEF -2#include<iostream>#include<cstdlib>#include <sstream>#include<cmath>using namespace std;struct Node{Node(){_count=0;for(int i=0;i<M+1;i++){_data[i]=DEF;_array[i]=0;}_array[M+1]=0;}int _count;int _data[M+1];Node* _array[M+2];};//用于叶节点中向后移动datavoid move_back(int* start,int count,int step=1){for(int i=count-1;i>=0;i--){*(start+i+step)=*(start+i);}}//用于分裂向上插入时父节点的向后移动void move_back(Node* node,int start,int step=1){node->_array[node->_count+step]=node->_array[node->_count];for(int i=node->_count-1;i>=start;i--){node->_data[i+step]=node->_data[i];node->_array[i+step]=node->_array[i];}}//用于叶节点中向前移动datavoid move_front(int* start,int count,int step=1){for(int i=0;i<count;i++){*(start+i-step)=*(start+i);}}//向前移动void move_front(Node* node,int start,int step=1){for(int i=start;i<node->_count;i++){node->_data[i-step]=node->_data[i];node->_array[i-step]=node->_array[i];}node->_array[node->_count-step]=node->_array[node->_count];}//二分定位int getPos(Node* node,int data){if(node==0){return -1;}int min=0;int max=node->_count-1;if(max<0){max=0;}while(min<max){int mid=(min+max)/2;if(data==node->_data[mid]){return mid;}else if(data<node->_data[mid]){max=mid-1;}else{min=mid+1;}}return min;}void print(Node* node){if(node==0){return;}cout<<"--------------------------"<<endl;cout<<node<<':'<<node->_count<<endl;for(int i=0;i<M+1;i++){cout<<node->_data[i]<<' ';}cout<<endl;for(int i=0;i<M+2;i++){cout<<node->_array[i]<<' ';}cout<<endl;cout<<"--------------------------"<<endl;for(int i=0;i<M+2;i++){print(node->_array[i]);}}void insert(Node*& node,Node*& parent,int pindex,int data){if(node->_count==0){node->_data[0]=data;node->_count++;return;}int pos=getPos(node,data);if(data<node->_data[pos]){if(node->_array[0]==0){if(pos<node->_count){move_back(&node->_data[pos],node->_count-pos);}node->_data[pos]=data;node->_count++;}else{insert(node->_array[pos],node,pos,data);}}else{if(node->_array[0]==0){if(pos+1<node->_count){move_back(&node->_data[pos+1],node->_count-pos-1);}node->_data[pos+1]=data;node->_count++;}else{insert(node->_array[pos+1],node,pos+1,data);}}//分裂检测if(node->_count==M+1){//构造兄弟节点Node* sib=new Node;int mid=M/2;int start=0;//将node右边 赋给sibsib->_array[mid]=node->_array[M+1];node->_array[M+1]=0;for(int i=mid+1;i<M+1;i++,start++){sib->_data[start]=node->_data[i];sib->_array[start]=node->_array[i];sib->_count++;node->_data[i]=DEF;node->_array[i]=0;node->_count--;}int data=node->_data[mid];node->_data[mid]=DEF;node->_count--;if(node==parent){//构造父节点Node* p=new Node;p->_count=1;p->_data[0]=data;p->_array[0]=node;p->_array[1]=sib;parent=p;}else{if(pindex<parent->_count){move_back(parent,pindex);//node 父节点从mid开始(包括node)整体被右移,但因为node右边已被移动到sib,所以必须在左边parent->_array[pindex]=parent->_array[pindex+1];}parent->_data[pindex]=data;parent->_array[pindex+1]=sib;parent->_count++;}//print(parent);}}void balance(Node* node,Node*& parent,int index){if(node==parent){if(parent->_count==0){Node* temp=parent;parent=parent->_array[0];delete temp;}return;}//1.1 没有左兄弟 那么一定是最左边的节点,此时查找右兄 整个只判断一边就行了,两边太麻烦if(index==0){Node* rsib=parent->_array[index+1];//1.1.1 兄弟有多于节点(节点数>=ceil(M+1)/2 -1 == 关键字数>=floor(M/2),现有关键字数应+1才能借位) 将父移动到删除节点,将兄弟上移动到父if(rsib->_count-1>=floor(M/2.0)){node->_data[node->_count]=parent->_data[index];node->_count++;node->_array[node->_count]=rsib->_array[0];parent->_data[index]=rsib->_data[0];move_front(rsib,1);rsib->_array[parent->_array[index+1]->_count]=0;rsib->_count--;rsib->_data[parent->_array[index+1]->_count]=DEF;}//1.1.2 兄弟没有多余节点 父节点上对应元素移动到node,将兄弟移动到node,删除兄弟else{node->_data[node->_count]=parent->_data[index];node->_count++;int start=node->_count;for(int i=0;i<rsib->_count;i++,start++){node->_data[start]=rsib->_data[i];node->_array[start]=rsib->_array[i];node->_count++;}node->_array[node->_count]=rsib->_array[rsib->_count];move_front(parent,1);parent->_array[parent->_count]=0;parent->_count--;parent->_data[parent->_count]=DEF;delete rsib;parent->_array[0]=node;}}else{Node* lsib=parent->_array[index-1];//1.2.1 兄弟有多于节点( 节点数>=ceil(M+1)/2 -1 == 关键字数>=floor(M/2),现有关键字数应+1才能借位) 将父移动到删除节点,将兄弟上移动到父if(lsib->_count-1>=floor(M/2.0)){move_back(node,0);node->_data[0]=parent->_data[index-1];node->_array[0]=lsib->_array[lsib->_count];node->_count++;parent->_data[index-1]=lsib->_data[lsib->_count-1];lsib->_array[lsib->_count]=0;lsib->_count--;lsib->_data[lsib->_count]=DEF;}//1.2.2 兄弟没有多余节点 父节点上对应元素移动到兄弟,将node移动到兄弟,删除nodeelse{lsib->_data[lsib->_count]=parent->_data[index-1];lsib->_count++;int start=lsib->_count;for(int i=0;i<node->_count;i++,start++){lsib->_data[start]=node->_data[i];lsib->_array[start]=node->_array[i];lsib->_count++;}lsib->_array[start]=node->_array[node->_count];move_front(parent,index);parent->_array[parent->_count]=0;parent->_count--;parent->_data[parent->_count]=DEF;delete node;parent->_array[index-1]=lsib;}}}void del_proc(Node* node,int pos){if(pos+1<node->_count){move_front(&node->_data[pos+1],node->_count-pos-1);}node->_count--;node->_data[node->_count]=DEF;}void next(Node* node,Node*& parent,int& ori,int pos){cout<<"next:"<<node<<endl;if(node->_array[0]==0){ori=node->_data[0];del_proc(node,0);}else{next(node->_array[0],node,ori,0);}//移动检测 根据B树定义,关键字数目应大于等于M/2if(node->_count<ceil(M/2.0)){balance(node,parent,pos);}}void del(Node*& node,Node*& parent,int index,int data){int pos=getPos(node,data);if(pos==-1){cout<<"i can't find it"<<endl;return;}if(data==node->_data[pos]){//处理节点//1.如果是叶节点 直接把元素删除if(node->_array[0]==0){del_proc(node,pos);}//2.如果是内节点 需后继或前驱删除else{next(node->_array[pos+1],node,node->_data[pos],pos+1);}}else if(data<node->_data[pos]){del(node->_array[pos],node,pos,data);}else{del(node->_array[pos+1],node,pos+1,data);}//移动检测 根据B树定义,关键字数目应大于等于M/2if(node->_count<ceil(M/2.0)){balance(node,parent,index);}}void find(Node* node,int data,stringstream& ss){int pos=getPos(node,data);if(pos==-1){cout<<"i can't find it"<<endl;return;}if(data==node->_data[pos]){ss<<pos;cout<<"i find it:"<<data<<" by path:"<<ss.str()<<endl;}else if(data<node->_data[pos]){ss<<pos<<',';find(node->_array[pos],data,ss);}else{ss<<pos+1<<',';find(node->_array[pos+1],data,ss);}}int main(){srand(time(0));Node* root=new Node;for(int i=0;i<16;i++){insert(root,root,0,rand()%32);}print(root);int data;while(true){cout<<"cin the num you want to del:"<<endl;cin>>data;del(root,root,0,data);print(root);}/*int data;stringstream ss;while(true){ss.str("");cout<<"cin the num you want to find:"<<endl;cin>>data;find(root,data,ss);}*/return 0;}



原创粉丝点击