b樹的實現(2)---java版程式碼
阿新 • • 發佈:2018-12-25
原文地址: http://blog.csdn.net/cdnight/article/details/10619599
[java] view plain copy print?- 感覺上,b樹的插入及刪除操作都不如RB樹複雜。當年插紅黑樹的各種操作解釋文章都不下幾十篇了,資料結構及演算法的除錯正確執行是一個大問題,因為錯誤往往出現在細微處。
- package BTree;
- publicclass indexUnit {
- publicfloat indexNo;
- public Object indexValue=new Object();
- }
[java] view plain copy print?
- package BTree;
- import java.util.ArrayList;
- publicclass TreeUnit {
- public TreeUnit _parent=null;
- public ArrayList<indexUnit> keys=new ArrayList<indexUnit>();
- public ArrayList<TreeUnit> childNodes=new ArrayList<TreeUnit>();
- }
[java] view plain copy print?
- package BTree;
- /**
- * Created with IntelliJ IDEA.
- * User: Administrator
- * Date: 13-8-19
- * Time: 上午10:21
- * To change this template use File | Settings | File Templates.
- */
- public
- public TreeUnit _btreeRootNode=new TreeUnit();
- /*
- * 請注意,這個是最多容納的子樹的階,b樹的階應該是最多的子樹數量,
- * 根據b樹的性質,最大主鍵數量+1=最多子樹數量。
- * 並且,任何時刻,主鍵的數量比下屬子樹數量少1.
- * */
- publicint _m=6;
- privateint _min=3;
- publicint totalKeys=1;
- /**
- * 確定該b樹的最大子節點數。
- * */
- public BtreeGen(int m){
- _m=m;
- _min=(int)Math.ceil((double)m/2);
- }
- publicboolean insert(float indexNO,Object indexValue){
- indexUnit iunit=new indexUnit();
- iunit.indexNo=indexNO;
- iunit.indexValue=indexValue;
- TreeUnit needInsertLeaf=recursion_insert_search_leaf_node(indexNO, _btreeRootNode);
- if(needInsertLeaf==null){
- //--
- System.out.println("【警告】找不到需要插入的葉節點!");
- returnfalse;
- }
- else{
- System.out.println("【提示】需要插入的葉節點為:");
- for(indexUnit iiUnit:needInsertLeaf.keys){
- //--
- System.out.print(" "+iiUnit.indexNo+" ");
- }
- }
- to_insert(indexNO, indexValue, needInsertLeaf);
- returntrue;
- }
- private TreeUnit recursion_insert_search_leaf_node(float indexNO,TreeUnit currentUnit){
- if(currentUnit==null){
- returnnull;
- }
- //--假如有下屬節點,那麼就必須跳到下一個點。
- if(currentUnit.childNodes.size()>0){
- int childLoc=0;
- int cindex=0;
- for(indexUnit iUnit:currentUnit.keys){
- if(iUnit.indexNo<indexNO){
- childLoc=cindex+1;
- }
- if(iUnit.indexNo==indexNO){
- //--已經包含該節點了?那麼就返回空,不要再插了。
- returnnull;
- }
- cindex++;
- }
- TreeUnit childTree=currentUnit.childNodes.get(childLoc);
- return recursion_insert_search_leaf_node(indexNO, childTree);
- }
- else{
- //--沒有下屬節點,那麼就認定是這個葉節點了。
- return currentUnit;
- }
- }
- /*
- * 主鍵的插入。
- * */
- privatevoid to_insert(float indexNO,Object value,TreeUnit currentUnit){
- int insertLoc=0;
- for(indexUnit iUnit:currentUnit.keys){
- if(iUnit.indexNo>indexNO){
- break;
- }
- insertLoc++;
- }
- indexUnit insertedUnit=new indexUnit();
- insertedUnit.indexNo=indexNO;
- insertedUnit.indexValue=value;
- currentUnit.keys.add(insertLoc, insertedUnit);
- if(currentUnit.keys.size()>_m-1){
- recursion_division(currentUnit);
- }
- else{
- return;
- }
- }
- privatevoid recursion_division(TreeUnit currentUnit){
- if(currentUnit==null){
- return;
- }
- if(currentUnit.keys.size()<=_m-1){
- return;
- }
- if(currentUnit._parent==null){
- System.out.println("沒有父節點。");
- TreeUnit leftTree=new TreeUnit();
- TreeUnit rightTree=new TreeUnit();
- leftTree._parent=currentUnit;
- rightTree._parent=currentUnit;
- indexUnit keyUnit=currentUnit.keys.get(_min-1);
- int cindex=0;
- for (indexUnit tmp:currentUnit.keys) {
- if(cindex<_min-1){
- leftTree.keys.add(tmp);
- }
- elseif(cindex>=_min){
- rightTree.keys.add(tmp);
- }
- cindex++;
- }
- int theSize=currentUnit.childNodes.size();
- currentUnit.keys.clear();
- currentUnit.keys.add(keyUnit);
- if(currentUnit.childNodes.size()>0){
- //--
- for(int ii=0;ii<theSize;ii++){
- if(ii<=_min-1){
- currentUnit.childNodes.get(ii)._parent=leftTree;
- leftTree.childNodes.add(currentUnit.childNodes.get(ii));
- }
- else{
- currentUnit.childNodes.get(ii)._parent=rightTree;
- rightTree.childNodes.add(currentUnit.childNodes.get(ii));
- }
- }
- }
- currentUnit.childNodes.clear();
- currentUnit.childNodes.add(leftTree);
- currentUnit.childNodes.add(rightTree);
- return;
- }
- System.out.println("父節點不為空。");
- //--分裂成為了舊節點及新節點兩個節點。
- indexUnit keyUnit=currentUnit.keys.get(_min-1);
- TreeUnit newTreeUnit=new TreeUnit();
- newTreeUnit._parent=currentUnit._parent;
- int cindex=0;
- for (indexUnit tmp:currentUnit.keys) {
- if(cindex>=_min){
- newTreeUnit.keys.add(tmp);
- }
- cindex++;
- }
- int theSize=currentUnit.keys.size();
- for(int i2=theSize-1;i2>=_min-1;i2--){
- currentUnit.keys.remove(i2);
- }
- cindex=0;
- theSize=currentUnit.childNodes.size();
- for(int ii4=theSize-1;ii4>=_min;ii4--){
- TreeUnit tmp2=currentUnit.childNodes.get(ii4);
- tmp2._parent=newTreeUnit;
- if(newTreeUnit.childNodes.size()<=0){
- newTreeUnit.childNodes.add(tmp2);
- }
- else{
- newTreeUnit.childNodes.add(0,tmp2);
- }
- }
- for(int ii3=theSize-1;ii3>=_min;ii3--){
- currentUnit.childNodes.remove(ii3);
- }
- int insertPLoc=0;
- cindex=0;
- for(indexUnit iUnit:currentUnit._parent.keys){
- if(iUnit.indexNo<keyUnit.indexNo){
- insertPLoc=cindex+1;
- }
- cindex++;
- }
- currentUnit._parent.keys.add(insertPLoc, keyUnit);
- currentUnit._parent.childNodes.add(insertPLoc+1, newTreeUnit);
- //--給父節點新增相應子節點。
- if(currentUnit._parent.keys.size()>_m-1){
- recursion_division(currentUnit._parent);
- }
- return;
- }
- public indexUnit search(float indexNO){
- _searchResultUnit=null;
- recursion_search(_btreeRootNode,indexNO);
- return _searchResultUnit;
- }
- private indexUnit _searchResultUnit=null;
- privatevoid recursion_search(TreeUnit currentUnit, float indexNO){
- if(currentUnit==null){
- _searchResultUnit=null;
- return;
- }
- for(indexUnit f1:currentUnit.keys){
- if(f1.indexNo==indexNO){
- _searchResultUnit=f1;
- return;
- }
- }
- //--假如上面都找不到,並且該節點下面沒有子樹了,那麼就表示沒有這個東西。
- if(currentUnit.childNodes.size()<=0){
- return;
- }
- int childTreeIndex=0;
- int ccIndex=0;
- for(indexUnit f2:currentUnit.keys){
- if(f2.indexNo<indexNO){
- childTreeIndex=ccIndex+1;
- }
- ccIndex++;
- }
- TreeUnit childTreeUnit=currentUnit.childNodes.get(childTreeIndex);
- recursion_search(childTreeUnit, indexNO);
- }
- private TreeUnit _result_treeUnit=null;
- /**
- * 獲取indexNO所在的節點。
- * */
- public TreeUnit getSearchNode(float indexNO){
- _result_treeUnit=null;
- recursion_search_node(_btreeRootNode, indexNO);
- return _result_treeUnit;
- }
- /**
- *搜查indexNO所在的節點。
- * */
- privatevoid recursion_search_node(TreeUnit treeUnit,float indexNO){
- if(treeUnit==null){
- return;
- }
- int childChosenIndex=0;
- int cindex=0;
- for(indexUnit iTMP:treeUnit.keys){
- if(indexNO>iTMP.indexNo){
- childChosenIndex=cindex+1;
- }
- if(iTMP.indexNo==indexNO){
- _result_treeUnit=treeUnit;
- return;
- }
- cindex++;
- }
- if(treeUnit.childNodes.size()<=0){
- return;
- }
- //--假如有下面並且當前沒包含相關主鍵,那麼就搜尋下面子節點的。
- TreeUnit childTreeUnit=treeUnit.childNodes.get(childChosenIndex);
- recursion_search_node(childTreeUnit, indexNO);
- }
- publicint[] getRoute(float indexNO){
- returnnull;
- }
- publicboolean delete(float indexNO){
- TreeUnit needDelNode=getSearchNode(indexNO);
- if(needDelNode==null){
- returnfalse;
- }
- return deleteNode(needDelNode, indexNO);
- }
- /**
- * 刪除相關節點。
- * 刪除有幾種情況:
- * 1、假如是葉節點,並且刪除以後符合b樹的性質,譬如:m=6---最大主鍵數量為5,最少主鍵數量為2,葉節點刪除主鍵後,假如關鍵字數量》=2,那麼就完成刪除操作,
- * 否則:
- * 1、看看有沒有左右節點,假如左右節點有空餘的關鍵字,那麼就借用相應的關鍵字,
- * 假如左右節點的關鍵字數量都是2,沒有空餘的,那麼只能想父節點借用,並且可能會發生合併操作。
- *
- * */
- publicboolean deleteNode(TreeUnit needDelNode,float indexNO){
- //System.out.println("需要刪除的節點為:"+needDelNode.keys.get(0).indexNo);
- //--找到當前關鍵字的在節點裡面的位置。
- int indexLoc=-1;
- int cindex=0;
- for(indexUnit iUnit:needDelNode.keys){
- if(iUnit.indexNo==indexNO){
- indexLoc=cindex;
- }
- cindex++;
- }
- if(indexLoc==-1){
- returnfalse;
- }
- TreeUnit leftChildNode=null;
- TreeUnit rightChildNode=null;
- if(needDelNode.childNodes.size()>0){
- leftChildNode=needDelNode.childNodes.get(indexLoc);
- rightChildNode=needDelNode.childNodes.get(indexLoc+1);
- }
- /**
- * 假如關鍵字所在節點為根節點,並且沒有任何下屬節點,那麼就直接刪除好了。
- * */
- if(needDelNode._parent==null&&(needDelNode.childNodes==null||needDelNode.childNodes.size()<=0)){
- needDelNode.keys.remove(indexLoc);
- returntrue;
- }
- /**
- * 假如關鍵字包含子節點,那麼就進行相關調整,需要遞迴調整到葉子節點為止。請注意,現在只是調整調換關鍵字的數值,並沒有刪除任何關鍵字,所以
- * b樹的結構沒有破壞。
- * */
- /**
- * a.如果x的左孩子節點存在,x->child[i],並且x->child[i]的節點關鍵字個數至少是n個,
- * 則找到 child[i]中最大的關鍵字max替換x中刪除的關鍵字,繼續遞迴child[i]刪除關鍵字max。
- * 這一段話引用自網上,但是我想說,假如該節點不是葉子節點,那麼對於該節點的某一個關鍵字keys[i],
- * 其左子結點及右子節點child[i]與child[i+1]必然存在----這是b樹的基本性質。
- * */
- if(needDelNode.childNodes!=null&&needDelNode.childNodes.size()>0){
- //假如左節點有空餘的關鍵字可以使用(解釋:對於6階b樹--最多6個子樹,每個節點最少有3棵子樹,最多5個節點,最少2個節點,有空餘關鍵字是指關鍵字數量大於或等於3個)
- if(leftChildNode!=null&&leftChildNode.keys.size()>=_min){
- int leftLastIndex=leftChildNode.keys.size()-1;
- needDelNode.keys.remove(indexLoc);
- needDelNode.keys.add(indexLoc,leftChildNode.keys.get(leftLastIndex));
- float indexNO1=needDelNode.keys.get(indexLoc).indexNo;
- //--遞迴執行
- return deleteNode(leftChildNode, indexNO1);
- }
- //--假如右側節點有關鍵字空餘
- elseif(rightChildNode.keys.size()>=_min){
- int rightLastIndex=0;
- needDelNode.keys.remove(indexLoc);
- needDelNode.keys.add(indexLoc, rightChildNode.keys.get(0));
- return deleteNode(rightChildNode, rightChildNode.keys.get(0).indexNo);
- }
- else{
- //--假如左右子節點都沒有空餘節點了,那麼只能合併了。
- leftChildNode.keys.add(needDelNode.keys.get(indexLoc));
- for(indexUnit iUnit:rightChildNode.keys){
- leftChildNode.keys.add(iUnit);
- }
- for(TreeUnit item1:rightChildNode.childNodes){
- leftChildNode.childNodes.add(item1);
- }
- needDelNode.keys.remove(indexLoc);
- needDelNode.childNodes.remove(indexLoc+1);
- //--檢查父節點是否符合性質,是否需要回溯合併節點。
- /**
- * 請注意:這個地方是造成回溯合併的主要情形。
- * */
- recursion_checkCombination(needDelNode);
- return deleteNode(leftChildNode, indexNO);
- }
- }
- /**
- *
- * 假如是葉子節點,那麼就執行相關操作。
- *
- * */
- elseif(needDelNode.childNodes==null||needDelNode.childNodes.size()<=0){
- if(needDelNode.keys.size()>=_min){
- needDelNode.keys.remove(indexLoc);
- returntrue;
- }
- //---
- TreeUnit leftBrother=null;
- TreeUnit rightBrother=null;
- TreeUnit parentNode=needDelNode._parent;
- int childIndexLoc=parentNode.childNodes.indexOf(needDelNode);
- int keyIndexLoc=-1;
- if(childIndexLoc==0){
- rightBrother=parentNode.childNodes.get(1);
- }
- elseif(childIndexLoc==parentNode.childNodes.size()-1){
- leftBrother=parentNode.childNodes.get(childIndexLoc-1);
- }
- else{
- leftBrother=parentNode.childNodes.get(childIndexLoc-1);
- rightBrother=parentNode.childNodes.get(childIndexLoc+1);
- }
- //--假如左側兄弟存在並且有多餘節點那麼就借用了。
- if(leftBrother!=null&&leftBrother.keys.size()>=_min){
- keyIndexLoc=childIndexLoc-1;
- needDelNode.keys.add(0,parentNode.keys.get(keyIndexLoc));
- parentNode.keys.remove(keyIndexLoc);
- parentNode.keys.add(keyIndexLoc,leftBrother.keys.get(leftBrother.keys.size()-1));
- leftBrother.keys.remove(leftBrother.keys.size()-1);
- return deleteNode(needDelNode, indexNO);
- }
- //右側兄弟有多餘的。
- elseif(rightBrother!=null&&rightBrother.keys.size()>=_min){
- keyIndexLoc=childIndexLoc;
- needDelNode.keys.add(parentNode.keys.get(keyIndexLoc));
- parentNode.keys.add(keyIndexLoc,rightBrother.keys.get(0));
- parentNode.keys.remove(keyIndexLoc+1);
- rightBrother.keys.remove(0);///-------------
- return deleteNode(needDelNode, indexNO);
- }
- //--兩個兄弟都沒有多餘的,那麼就合併好了。
- else{
- if(leftBrother!=null){
- //leftBrother.keys.add(parentNode.keys.get(keyIndexLoc));
- keyIndexLoc=childIndexLoc-1;
- leftBrother.keys.add(parentNode.keys.get(keyIndexLoc));
- for(indexUnit iUnit:needDelNode.keys){
- leftBrother.keys.add(iUnit);
- }
- parentNode.keys.remove(keyIndexLoc);
- parentNode.childNodes.remove(keyIndexLoc+1);
- recursion_checkCombination(parentNode);
- deleteNode(leftBrother, indexNO);
- returntrue;
- }
- elseif(rightBrother!=null){
- //needDelNode.keys.remove(indexLoc);
- keyIndexLoc=childIndexLoc;
- needDelNode.keys.add(parentNode.keys.get(keyIndexLoc));
- for(indexUnit iUnit:rightBrother.keys){
- needDelNode.keys.add(iUnit);
- }
- parentNode.keys.remove(keyIndexLoc);
- parentNode.childNodes.remove(keyIndexLoc+1);
- recursion_checkCombination(parentNode);
- deleteNode(needDelNode, indexNO);
- returntrue;
- }
- else{
- returnfalse;
- }
- }
- }
- returntrue;
- }
- privatevoid recursion_checkCombination(TreeUnit currentUnit){
- if(currentUnit==null){
- return;
- }
- if(currentUnit._parent==null&¤tUnit.childNodes.size()<=1){
- //假如當前節點為根節點,並且沒有關鍵字,那麼根節點丟棄,採用新的根節點。
- _btreeRootNode=currentUnit.childNodes.get(0);
- _btreeRootNode._parent=null;
- return;
- }
- //假如當前節點為根節點,並且關鍵字為一,那麼就不管了,符合性質。
- if(currentUnit._parent==null){
- return;
- }
- if(currentUnit.keys.size()>=_min-1){
- return;
- }
- //假如不為根節點,並且節點的關鍵字小於_min-1,那麼必須再回溯遞迴合併。
- /**
- * 分幾種情況,假如左側子節點有空餘關鍵字,那麼從左側節點借,假如右側節點有空餘關鍵字,那麼從右側節點借,
- * 否則兩邊都沒有隻能繼續遞迴合併了。
- * */
- TreeUnit parentNode=currentUnit._parent;
- int indexLOC=currentUnit._parent.childNodes.indexOf(currentUnit);
- int keyIndexLOC=-1;
- int childIndexLOC=indexLOC;
- TreeUnit leftBrother=null;
- TreeUnit rightBrother=null;
- if(parentNode.childNodes.size()==2){
- if(childIndexLOC==0){
- rightBrother=parentNode.childNodes.get(1);
- }
- else{
- leftBrother=parentNode.childNodes.get(0);
- }
- }
- elseif(parentNode.childNodes.size()>=3){
- if(childIndexLOC==0){
- rightBrother=parentNode.childNodes.get(1);
- }
- elseif(childIndexLOC==parentNode.childNodes.size()-1){
- leftBrother=parentNode.childNodes.get(childIndexLOC-1);
- }
- else{
- leftBrother=parentNode.childNodes.get(childIndexLOC-1);
- rightBrother=parentNode.childNodes.get(childIndexLOC+1);
- }
- }
- //--左邊兄弟節點有餘錢,那麼就借。
- if(leftBrother!=null&&leftBrother.keys.size()>=_min){
- keyIndexLOC=childIndexLOC-1;
- currentUnit.keys.add(0, parentNode.keys.get(keyIndexLOC));
- currentUnit.childNodes.add(0,leftBrother.childNodes.get(leftBrother.childNodes.size()-1));
- parentNode.keys.remove(keyIndexLOC);
- parentNode.keys.add(keyIndexLOC,leftBrother.keys.get(leftBrother.keys.size()-1));
- leftBrother.keys.remove(leftBrother.keys.size()-1);
- leftBrother.childNodes.remove(leftBrother.childNodes.size()-1);
- return;
- }
- //--右邊兄弟有餘錢,那麼就借
- elseif(rightBrother!=null&&rightBrother.keys.size()>=_min){
- keyIndexLOC=childIndexLOC;
- currentUnit.keys.add(parentNode.keys.get(keyIndexLOC));
- currentUnit.childNodes.add(rightBrother.childNodes.get(0));
- parentNode.keys.remove(keyIndexLOC);
- parentNode.keys.add(rightBrother.keys.get(0));
- rightBrother.keys.remove(0);
- rightBrother.childNodes.remove(0);
- return;
- }
- //--大家都沒得借,那麼就只能遞迴合併了。
- else{
- //--有左側兄弟
- if(leftBrother!=null){
- keyIndexLOC=childIndexLOC-1;
- leftBrother.keys.add(parentNode.keys.get(keyIndexLOC));
- for(indexUnit iUnit:currentUnit.keys){
- leftBrother.keys.add(iUnit);
- }
- for(TreeUnit tUnit:currentUnit.childNodes){
- leftBrother.childNodes.add(tUnit);
- tUnit._parent=leftBrother;
- }
- parentNode.keys.remove(keyIndexLOC);
- parentNode.childNodes.remove(keyIndexLOC+1);
- recursion_checkCombination(parentNode);
- return;
- }
- else{
- //--有右側兄弟
- keyIndexLOC=childIndexLOC;
- currentUnit.keys.add(parentNode.keys.get(keyIndexLOC));
- for(indexUnit iUnit:rightBrother.keys){
- currentUnit.keys.add(iUnit);
- }