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-樹的平衡)
/**<br /> * 儲存int的集合<br /> * 集合中的元素存放在B-樹中<br /> *<br /> * @author dou<br /> *<br /> */<br />public class IntBalancedSet implements Cloneable{ </p><p> private static final int MINIMUM =2;//非根節點中最少存放的元素個數<br /> private static final int MAXIMUM = 2*MINIMUM;//節點中最多存放的元素個數<br /> int dataCount;//存放節點中元素的個數<br /> int[] data;<br /> int childCount;//存放節點中子樹的個數<br /> IntBalancedSet [] subset;<br /> /**<br /> * 為數組提供額外的空間,方便對數組進行刪除和添加操作<br /> */<br /> public IntBalancedSet(){<br /> data =new int[MAXIMUM+1];<br /> subset=new IntBalancedSet[MAXIMUM + 2];<br /> }<br /> /**<br /> * 在集合中添加新元素<br /> * @param element<br /> */<br /> public void add(int element){<br /> looseAdd(element);<br /> /*<br /> * 如果根節點比MAXIMUM大時,將根節點複製給一個新節點.並清空根節點.將新節點作為個根節點的<br /> * 子樹節點.再對此子節點進行拆分.<br /> * B-數只在根節點處才能增加高度<br /> */<br /> if(dataCount>MAXIMUM){<br /> IntBalancedSet cpy=copyData();<br /> data =new int[MAXIMUM+1];<br /> dataCount=0;<br /> childCount=dataCount+1;<br /> subset=new IntBalancedSet[MAXIMUM + 2];<br /> subset[0]=cpy;<br /> fixExcess(0);<br /> }<br /> }<br /> /**<br /> * B-樹是有效的前提下,可以調用此方法.<br /> * 如果elememt在集合中存在.那麼集合不變.否則,該元素添加到集合中.並且集合的根節點元素<br /> * 數目允許比MAXIMUM大1<br /> * @param element<br /> */<br /> private void looseAdd(int element){<br /> int i=firstGE(element);<br /> if(i==dataCount){<br /> if(childCount==0){<br /> insertEle(element, i);<br /> }<br /> else{<br /> subset[i].looseAdd(element);<br /> fixExcess(i);<br /> }<br /> }else{<br /> if(data[i]==element){<br /> return;<br /> }else{<br /> if(childCount==0){<br /> insertEle(element, i);<br /> }<br /> else{<br /> subset[i].looseAdd(element);<br /> fixExcess(i);<br /> }<br /> }<br /> }<br /> }<br /> /**<br /> * 將element插入到locale位置.其後的元素往後移<br /> * @param element<br /> * @param locale<br /> */<br /> private void insertEle(int element,int locale){<br /> for(int i=dataCount;i>locale;i--){<br /> data[i]=data[i-1];<br /> }<br /> data[locale]=element;<br /> dataCount++;<br /> //System.out.println(dataCount+" "+childCount);<br /> }<br /> /**<br /> * 將subset[i]拆分為兩個元素個數為MINIMUM,子樹數目為MINIMUM+1的兩個節點.<br /> * 分別存放在set1,和set2<br /> * @param set1<br /> * @param set2<br /> * @param i<br /> */<br /> private void divoteSub(IntBalancedSet set1,IntBalancedSet set2,int i){<br /> System.arraycopy(subset[i].data,0, set1.data, 0, MINIMUM);<br /> System.arraycopy(subset[i].subset,0, set1.subset, 0, MINIMUM+1);<br /> System.arraycopy(subset[i].data, MINIMUM+1, set2.data, 0, MINIMUM);<br /> System.arraycopy(subset[i].subset,MINIMUM+1, set2.subset, 0, MINIMUM+1);<br /> set1.dataCount=MINIMUM;<br /> set1.childCount=subset[i].childCount/2;<br /> set2.dataCount=MINIMUM;<br /> set2.childCount=subset[i].childCount/2; </p><p> }<br /> /**<br /> * 調用此方法必須保證除了subset[i]有MAXIMUM+1個元素外,整棵B-樹仍然有效<br /> * 將subset[i]拆分為兩個元素個數為MINIMUM的節點.在將節點插入到根節點的i和i+1位置<br /> * @param i<br /> */<br /> private void fixExcess(int i){<br /> if(subset[i].dataCount>MAXIMUM){<br /> IntBalancedSet set1=new IntBalancedSet();<br /> IntBalancedSet set2=new IntBalancedSet();<br /> insertEle(subset[i].data[MINIMUM], i);//在父節點插入該中間元素.<br /> divoteSub(set1, set2, i);<br /> subset[i]=set1;<br /> for(int j=childCount;j>i+1;j--){<br /> subset[j]=subset[j-1];<br /> }<br /> subset[i+1]=set2;<br /> childCount++;<br /> //System.out.println(data[0]);<br /> }<br /> }<br /> /**<br /> * 返回一個新的引用中的data和subset指向當前節點的data和subset;<br /> * @return<br /> */<br /> private IntBalancedSet copyData(){<br /> IntBalancedSet copy;<br /> copy=new IntBalancedSet();<br /> copy.data=data;<br /> copy.dataCount=dataCount;<br /> copy.childCount=childCount;<br /> copy.subset=subset;<br /> return copy;<br /> } </p><p> public Object clone(){<br /> IntBalancedSet copy;<br /> copy=new IntBalancedSet();<br /> copy.data=data.clone();<br /> copy.dataCount=dataCount;<br /> copy.childCount=childCount;<br /> copy.subset=subset.clone();<br /> return copy; </p><p> }<br /> /**<br /> * 在B-樹中尋找target.<br /> * @param target<br /> * @return<br /> */<br /> public boolean contains(int target){<br /> int i=firstGE(target);<br /> //System.out.println("i:"+i);<br /> if(i==dataCount){<br /> if(childCount==0)<br /> return false;<br /> else<br /> return subset[i].contains(target);<br /> }<br /> else{<br /> if(target==data[i])<br /> {<br /> return true;<br /> }<br /> else{<br /> if(childCount==0)<br /> return false;<br /> else<br /> return subset[i].contains(target);<br /> } </p><p> }<br /> }<br /> /**<br /> * 返回根節點中第一個大於或等於target的元素的位置<br /> * 如果沒有這樣的元素,則返回dataCount<br /> * @param target<br /> * @return<br /> */<br /> private int firstGE(int target){<br /> int i=0;<br /> for(;i<dataCount;i++){<br /> if(data[i]>=target)<br /> return i;<br /> }<br /> return i;<br /> }<br /> /**<br /> * 在集合中刪除元素<br /> * @param target<br /> * @return<br /> */<br /> public boolean remove(int target){<br /> boolean answer = looseRemove(target);<br /> /**<br /> * 如果根節點沒有元素,並且僅有一個子節點.那麼刪除子節點<br /> */<br /> if((dataCount==0)&&(childCount==1)){<br /> dataCount=subset[0].dataCount;<br /> childCount=subset[0].childCount;<br /> data=subset[0].data;<br /> subset=subset[0].subset;<br /> }<br /> return answer;<br /> }<br /> /**<br /> * 如果target在集合中,將他刪除並返回true.否則返回false<br /> * 執行該方法後根節點的元素數目可能比MINIMUM小1<br /> * @param target<br /> * @return<br /> */ </p><p> private boolean looseRemove(int target){<br /> int i=firstGE(target);<br /> if(childCount==0){<br /> if(i!=dataCount&&data[i]==target){<br /> //在data[i]中找到元素.並且沒有子節點<br /> cover(i);<br /> return true;<br /> }else{<br /> return false;<br /> }<br /> }else{<br /> if(i!=dataCount&&data[i]==target){<br /> /**<br /> * 在data[i]中找到元素.但有子節點.將子節點中的最大元素覆蓋i.既在所有比<br /> * data[i]小的元素集合中的最大值.<br /> * subset[i]的元素數目能比最小值小1<br /> */ </p><p> data[i]= subset[i].removeBiggest();<br /> if(subset[i].dataCount<MINIMUM)<br /> fixShortage(i);<br /> return true;<br /> }<br /> else{<br /> /**<br /> * 在data[i]中找不到元素.但有子節點.遞迴調用子節點的該方法.<br /> */<br /> boolean answer=subset[i].looseRemove(target);<br /> if(subset[i].dataCount<MINIMUM)<br /> fixShortage(i);<br /> return answer;<br /> }<br /> }<br /> }<br /> /**<br /> * 當subset[i]只有MINIMUM-1個元素時調用此方法<br /> * 該方法使根節點的元素個數比MINIMU小1<br /> * @param i<br /> */<br /> private void fixShortage(int i){ </p><p> if(i!=0&&subset[i-1].dataCount>MINIMUM){<br /> /**<br /> * 如果subset[i-1]的元素數目比MINIMUM大.那麼將data[i-1]的值插入到subset[i]<br /> * 的data[0]位置.再將subset[i-1]的最後個元素轉移到data[i-1]的位置.如果subset[i-1]<br /> * 有子樹那麼將subset[i-1]的最大子樹添加到subset[i]的subset[0]位置.<br /> *<br /> */<br /> subset[i].insertEle(data[i-1], 0);<br /> data[i-1]=subset[i-1].cover(subset[i-1].dataCount-1);<br /> if(subset[i-1].childCount!=0){<br /> subset[i].addSubset(subset[i-1].coverSub(subset[i-1].childCount-1),0);<br /> }<br /> return;<br /> }<br /> if(i!=0&&subset[i-1].dataCount==MINIMUM){<br /> subset[i-1].insertEle(data[i-1], subset[i-1].dataCount);<br /> cover(i-1);<br /> combineSub(subset[i-1],subset[i]);<br /> coverSub(i);<br /> return ;<br /> }<br /> if(i<dataCount&&subset[i+1].dataCount>MINIMUM){<br /> subset[i].insertEle(data[i], subset[i].dataCount);<br /> data[i]=subset[i+1].cover(0);<br /> if(subset[i+1].childCount!=0){<br /> subset[i].addSubset(subset[i+1].coverSub(0), subset[i].childCount);<br /> }<br /> return;<br /> }<br /> if(i<dataCount&&subset[i+1].dataCount==MINIMUM){<br /> subset[i+1].insertEle(data[i], 0);<br /> cover(i);<br /> combineSub(subset[i],subset[i+1]);<br /> coverSub(i+1);<br /> return;<br /> } </p><p> } </p><p> private int removeBiggest(){<br /> if(childCount==0){ </p><p> return data[--dataCount];<br /> }else{<br /> int answer = subset[childCount-1].removeBiggest();<br /> if(subset[childCount-1].dataCount<MINIMUM){<br /> fixShortage(childCount-1);<br /> }<br /> return answer;<br /> } </p><p> } </p><p> /**<br /> * 將set2的元素和孩子節點添加到set1的後面;保證set1+set2的元素和不大於MAXIMUM<br /> * @param set1<br /> * @param set2<br /> */<br /> private void combineSub(IntBalancedSet set1,IntBalancedSet set2){ </p><p> for(int i=0;i<set2.dataCount;i++){<br /> //System.out.println(" combineSub "+set1.dataCount+" "+set2.dataCount);<br /> set1.data[set1.dataCount++]=set2.data[i];<br /> }<br /> for(int i=0;i<set2.childCount;i++){<br /> set1.subset[set1.childCount++]=set2.subset[i];<br /> }<br /> }<br /> /**<br /> * 刪除節點中i位置的子節點.其後的子節點往前移動一個位置.<br /> * @param i<br /> */<br /> private IntBalancedSet coverSub(int i){<br /> IntBalancedSet answer=subset[i];<br /> for(int j=i;j<childCount;j++){<br /> subset[j]=subset[j+1];<br /> }<br /> childCount--;<br /> return answer;<br /> }<br /> /**<br /> * 刪除節點中i位置的元素.其後的元素往前移動一個位置.<br /> * @param i<br /> */<br /> private int cover(int i){<br /> int answer=data[i];<br /> for(int j=i;j<dataCount;j++){<br /> data[j]=data[j+1];<br /> }<br /> dataCount--;<br /> return answer;<br /> }<br />// private void tranferEle(int i,int flag){<br />// int dl=i+(flag==-1?0:flag);//datalocation<br />// subset[i].insertEle(data[dl], 0);<br />// data[dl]=subset[i+flag].data];<br />// if(subset[i-1].childCount!=0){<br />// subset[i-1].addSubset(subset[subset[i-1].childCount--],0);<br />// }<br />// }<br /> /**<br /> * 調用該方法的節點必須保證其子節點的數目比B-樹要求的少一<br /> * 調用後將sub添加到l位置.原本l後的節點往後移一個位置<br /> * @param sub<br /> * @param l<br /> */<br /> private void addSubset(IntBalancedSet sub,int l){<br /> for(int i=childCount;i>l;i--){<br /> subset[i]=subset[i-1];<br /> }subset[l]=sub;<br /> childCount++;<br /> }<br />// private int removeLastest(){<br />//<br />// }<br /> public void print(int indent){<br /> final int EXTRA_INDENTATION=4;<br /> int i;<br /> int space;<br /> for(space=0;space<indent;space++){<br /> System.out.print(" ");<br /> }<br /> for(i=0;i<dataCount;i++){<br /> System.out.print(data[i]+",");<br /> }<br /> System.out.print("DC:"+dataCount+" CC:"+childCount);<br /> System.out.println();<br /> for(i=childCount-1;i>=0;i--){<br /> subset[i].print(indent+EXTRA_INDENTATION);<br /> }<br />}<br />public static void main (String [] args) {<br />IntBalancedSet set = new IntBalancedSet();<br />Random rg = new Random();<br />for (int x=0; x<2000; x++)<br />{<br />int num = rg.nextInt(10000);<br />System.out.println("Adding " + num);<br />set.add(num);<br />//System.out.println("tree so far:");<br />//set.print(4);<br />}<br />System.out.println("final version of tree");<br />set.print(4);<br />int num = rg.nextInt(10000);<br />if (set.contains(num))<br />System.out.println ("found it!");<br />else<br />System.out.println ("all that time, and nothing to show for it!");</p><p> }<br />} </p><p>