B-树

发布时间:2014-10-25 2:20:01
来源:分享查询网

  R-Bayer和M.McCreight 于1972年提出 B-树中节点的元素个数由一个MINIMUM的正整数决定   B-树规则1: 节点至少包含MINIMUM个元素.根节点不受此限制 B-树规则2: 节点至多可以包含的元素个数为2*MIMNIMUM B-树规则3: B-树中每个节点的元素按从小到大的顺序存放在数组中,数组可以没有存满 B-树规则4: 非叶子节点的子树数目比该节点的元素数目大1 B-树规则5: 对于任何非叶子节点第i号元素比该节点的<=i号子树的所有元素都要大.比该节点的任何<i号的子树所有元素都要小 B-树规则6: B-树中的叶子有相同的深度(保证了B-树的平衡)     /** * 保存int的集合 * 集合中的元素存放在B-树中 * * @author dou * */ public class IntBalancedSet implements Cloneable{ private static final int MINIMUM =2;//非根节点中最少存放的元素个数 private static final int MAXIMUM = 2*MINIMUM;//节点中最多存放的元素个数 int dataCount;//存放节点中元素的个数 int[] data; int childCount;//存放节点中子树的个数 IntBalancedSet [] subset; /** * 为数组提供额外的空间,方便对数组进行删除和添加操作 */ public IntBalancedSet(){ data =new int[MAXIMUM+1]; subset=new IntBalancedSet[MAXIMUM + 2]; } /** * 在集合中添加新元素 * @param element */ public void add(int element){ looseAdd(element); /* * 如果根节点比MAXIMUM大时,将根节点复制给一个新节点.并清空根节点.将新节点作为个根节点的 * 子树节点.再对此子节点进行拆分. * B-数只在根节点处才能增加高度 */ if(dataCount>MAXIMUM){ IntBalancedSet cpy=copyData(); data =new int[MAXIMUM+1]; dataCount=0; childCount=dataCount+1; subset=new IntBalancedSet[MAXIMUM + 2]; subset[0]=cpy; fixExcess(0); } } /** * B-树是有效的的前提下,可以调用此方法. * 如果elememt在集合中存在.那么集合不变.否则,该元素添加到集合中.并且集合的根节点元素 * 数目允许比MAXIMUM大1 * @param element */ private void looseAdd(int element){ int i=firstGE(element); if(i==dataCount){ if(childCount==0){ insertEle(element, i); } else{ subset[i].looseAdd(element); fixExcess(i); } }else{ if(data[i]==element){ return; }else{ if(childCount==0){ insertEle(element, i); } else{ subset[i].looseAdd(element); fixExcess(i); } } } } /** * 将element插入到locale位置.其后的元素往后移 * @param element * @param locale */ private void insertEle(int element,int locale){ for(int i=dataCount;i>locale;i--){ data[i]=data[i-1]; } data[locale]=element; dataCount++; //System.out.println(dataCount+" "+childCount); } /** * 将subset[i]拆分为两个元素个数为MINIMUM,子树数目为MINIMUM+1的两个节点. * 分别存放在set1,和set2 * @param set1 * @param set2 * @param i */ private void divoteSub(IntBalancedSet set1,IntBalancedSet set2,int i){ System.arraycopy(subset[i].data,0, set1.data, 0, MINIMUM); System.arraycopy(subset[i].subset,0, set1.subset, 0, MINIMUM+1); System.arraycopy(subset[i].data, MINIMUM+1, set2.data, 0, MINIMUM); System.arraycopy(subset[i].subset,MINIMUM+1, set2.subset, 0, MINIMUM+1); set1.dataCount=MINIMUM; set1.childCount=subset[i].childCount/2; set2.dataCount=MINIMUM; set2.childCount=subset[i].childCount/2; } /** * 调用此方法必须保证除了subset[i]有MAXIMUM+1个元素外,整棵B-树仍然有效的 * 将subset[i]拆分为两个元素个数为MINIMUM的节点.在将节点插入到根节点的i和i+1位置 * @param i */ private void fixExcess(int i){ if(subset[i].dataCount>MAXIMUM){ IntBalancedSet set1=new IntBalancedSet(); IntBalancedSet set2=new IntBalancedSet(); insertEle(subset[i].data[MINIMUM], i);//在父节点插入该中间元素. divoteSub(set1, set2, i); subset[i]=set1; for(int j=childCount;j>i+1;j--){ subset[j]=subset[j-1]; } subset[i+1]=set2; childCount++; //System.out.println(data[0]); } } /** * 返回一个新的引用中的data和subset指向当前节点的data和subset; * @return */ private IntBalancedSet copyData(){ IntBalancedSet copy; copy=new IntBalancedSet(); copy.data=data; copy.dataCount=dataCount; copy.childCount=childCount; copy.subset=subset; return copy; } public Object clone(){ IntBalancedSet copy; copy=new IntBalancedSet(); copy.data=data.clone(); copy.dataCount=dataCount; copy.childCount=childCount; copy.subset=subset.clone(); return copy; } /** * 在B-树中查找target. * @param target * @return */ public boolean contains(int target){ int i=firstGE(target); //System.out.println("i:"+i); if(i==dataCount){ if(childCount==0) return false; else return subset[i].contains(target); } else{ if(target==data[i]) { return true; } else{ if(childCount==0) return false; else return subset[i].contains(target); } } } /** * 返回根节点中第一个大于或等于target的元素的位置 * 如果没有这样的元素,则返回dataCount * @param target * @return */ private int firstGE(int target){ int i=0; for(;i<dataCount;i++){ if(data[i]>=target) return i; } return i; } /** * 在集合中删除元素 * @param target * @return */ public boolean remove(int target){ boolean answer = looseRemove(target); /** * 如果根节点没有元素,并且仅有一个子节点.那么删除子节点 */ if((dataCount==0)&&(childCount==1)){ dataCount=subset[0].dataCount; childCount=subset[0].childCount; data=subset[0].data; subset=subset[0].subset; } return answer; } /** * 如果target在集合中,将他删除并返回true.否则返回false * 执行该方法后根节点的元素数目可能比MINIMUM小1 * @param target * @return */ private boolean looseRemove(int target){ int i=firstGE(target); if(childCount==0){ if(i!=dataCount&&data[i]==target){ //在data[i]中找到元素.并且没有子节点 cover(i); return true; }else{ return false; } }else{ if(i!=dataCount&&data[i]==target){ /** * 在data[i]中找到元素.但有子节点.将子节点中的最大元素覆盖i.既在所有比 * data[i]小的元素集合中的最大值. * subset[i]的元素数目能比最小值小1 */ data[i]= subset[i].removeBiggest(); if(subset[i].dataCount<MINIMUM) fixShortage(i); return true; } else{ /** * 在data[i]中找不到元素.但有子节点.递归调用子节点的该方法. */ boolean answer=subset[i].looseRemove(target); if(subset[i].dataCount<MINIMUM) fixShortage(i); return answer; } } } /** * 当subset[i]只有MINIMUM-1个元素时调用此方法 * 该方法使根节点的元素个数比MINIMU小1 * @param i */ private void fixShortage(int i){ if(i!=0&&subset[i-1].dataCount>MINIMUM){ /** * 如果subset[i-1]的元素数目比MINIMUM大.那么将data[i-1]的值插入到subset[i] * 的data[0]位置.再将subset[i-1]的最后个元素转移到data[i-1]的位置.如果subset[i-1] * 有子树那么将subset[i-1]的最大子树添加到subset[i]的subset[0]位置. * */ subset[i].insertEle(data[i-1], 0); data[i-1]=subset[i-1].cover(subset[i-1].dataCount-1); if(subset[i-1].childCount!=0){ subset[i].addSubset(subset[i-1].coverSub(subset[i-1].childCount-1),0); } return; } if(i!=0&&subset[i-1].dataCount==MINIMUM){ subset[i-1].insertEle(data[i-1], subset[i-1].dataCount); cover(i-1); combineSub(subset[i-1],subset[i]); coverSub(i); return ; } if(i<dataCount&&subset[i+1].dataCount>MINIMUM){ subset[i].insertEle(data[i], subset[i].dataCount); data[i]=subset[i+1].cover(0); if(subset[i+1].childCount!=0){ subset[i].addSubset(subset[i+1].coverSub(0), subset[i].childCount); } return; } if(i<dataCount&&subset[i+1].dataCount==MINIMUM){ subset[i+1].insertEle(data[i], 0); cover(i); combineSub(subset[i],subset[i+1]); coverSub(i+1); return; } } private int removeBiggest(){ if(childCount==0){ return data[--dataCount]; }else{ int answer = subset[childCount-1].removeBiggest(); if(subset[childCount-1].dataCount<MINIMUM){ fixShortage(childCount-1); } return answer; } } /** * 将set2的元素和孩子节点添加到set1的后面;保证set1+set2的元素和不大于MAXIMUM * @param set1 * @param set2 */ private void combineSub(IntBalancedSet set1,IntBalancedSet set2){ for(int i=0;i<set2.dataCount;i++){ //System.out.println(" combineSub "+set1.dataCount+" "+set2.dataCount); set1.data[set1.dataCount++]=set2.data[i]; } for(int i=0;i<set2.childCount;i++){ set1.subset[set1.childCount++]=set2.subset[i]; } } /** * 删除节点中i位置的子节点.其后的子节点往前移动一个位置. * @param i */ private IntBalancedSet coverSub(int i){ IntBalancedSet answer=subset[i]; for(int j=i;j<childCount;j++){ subset[j]=subset[j+1]; } childCount--; return answer; } /** * 删除节点中i位置的元素.其后的元素往前移动一个位置. * @param i */ private int cover(int i){ int answer=data[i]; for(int j=i;j<dataCount;j++){ data[j]=data[j+1]; } dataCount--; return answer; } // private void tranferEle(int i,int flag){ // int dl=i+(flag==-1?0:flag);//datalocation // subset[i].insertEle(data[dl], 0); // data[dl]=subset[i+flag].data]; // if(subset[i-1].childCount!=0){ // subset[i-1].addSubset(subset[subset[i-1].childCount--],0); // } // } /** * 调用该方法的节点必须保证其子节点的数目比B-树要求的少一 * 调用后将sub添加到l位置.原本l后的节点往后移一个位置 * @param sub * @param l */ private void addSubset(IntBalancedSet sub,int l){ for(int i=childCount;i>l;i--){ subset[i]=subset[i-1]; }subset[l]=sub; childCount++; } // private int removeLastest(){ // // } public void print(int indent){ final int EXTRA_INDENTATION=4; int i; int space; for(space=0;space<indent;space++){ System.out.print(" "); } for(i=0;i<dataCount;i++){ System.out.print(data[i]+","); } System.out.print("DC:"+dataCount+" CC:"+childCount); System.out.println(); for(i=childCount-1;i>=0;i--){ subset[i].print(indent+EXTRA_INDENTATION); } } }

返回顶部
查看电脑版