原文地址: http://blog.csdn.net/cdnight/article/details/10619599
版权声明:本文为博主原创文章,未经博主允许不得转载。
- 感觉上,b树的插入及删除操作都不如RB树复杂。当年插红黑树的各种操作解释文章都不下几十篇了,数据结构及算法的调试正确运行是一个大问题,因为错误往往出现在细微处。
- package BTree;
- public class indexUnit {
- public float indexNo;
- public Object indexValue=new Object();
- }
- package BTree;
- import java.util.ArrayList;
- public class TreeUnit {
- public TreeUnit _parent=null;
- public ArrayList<indexUnit> keys=new ArrayList<indexUnit>();
- public ArrayList<TreeUnit> childNodes=new ArrayList<TreeUnit>();
- }
- 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 class BtreeGen {
- public TreeUnit _btreeRootNode=new TreeUnit();
- /*
- * 请注意,这个是最多容纳的子树的阶,b树的阶应该是最多的子树数量,
- * 根据b树的性质,最大主键数量+1=最多子树数量。
- * 并且,任何时刻,主键的数量比下属子树数量少1.
- * */
- public int _m=6;
- private int _min=3;
- public int totalKeys=1;
- /**
- * 确定该b树的最大子节点数。
- * */
- public BtreeGen(int m){
- _m=m;
- _min=(int)Math.ceil((double)m/2);
- }
- public boolean 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("【警告】找不到需要插入的叶节点!");
- return false;
- }
- else{
- System.out.println("【提示】需要插入的叶节点为:");
- for(indexUnit iiUnit:needInsertLeaf.keys){
- //--
- System.out.print(" "+iiUnit.indexNo+" ");
- }
- }
- to_insert(indexNO, indexValue, needInsertLeaf);
- return true;
- }
- private TreeUnit recursion_insert_search_leaf_node(float indexNO,TreeUnit currentUnit){
- if(currentUnit==null){
- return null;
- }
- //--假如有下属节点,那么就必须跳到下一个点。
- 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){
- //--已经包含该节点了?那么就返回空,不要再插了。
- return null;
- }
- cindex++;
- }
- TreeUnit childTree=currentUnit.childNodes.get(childLoc);
- return recursion_insert_search_leaf_node(indexNO, childTree);
- }
- else{
- //--没有下属节点,那么就认定是这个叶节点了。
- return currentUnit;
- }
- }
- /*
- * 主键的插入。
- * */
- private void 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;
- }
- }
- private void 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);
- }
- else if(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;
- private void 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所在的节点。
- * */
- private void 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);
- }
- public int[] getRoute(float indexNO){
- return null;
- }
- public boolean delete(float indexNO){
- TreeUnit needDelNode=getSearchNode(indexNO);
- if(needDelNode==null){
- return false;
- }
- return deleteNode(needDelNode, indexNO);
- }
- /**
- * 删除相关节点。
- * 删除有几种情况:
- * 1、假如是叶节点,并且删除以后符合b树的性质,譬如:m=6---最大主键数量为5,最少主键数量为2,叶节点删除主键后,假如关键字数量》=2,那么就完成删除操作,
- * 否则:
- * 1、看看有没有左右节点,假如左右节点有空余的关键字,那么就借用相应的关键字,
- * 假如左右节点的关键字数量都是2,没有空余的,那么只能想父节点借用,并且可能会发生合并操作。
- *
- * */
- public boolean 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){
- return false;
- }
- 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);
- return true;
- }
- /**
- * 假如关键字包含子节点,那么就进行相关调整,需要递归调整到叶子节点为止。请注意,现在只是调整调换关键字的数值,并没有删除任何关键字,所以
- * 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);
- }
- //--假如右侧节点有关键字空余
- else if(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);
- }
- }
- /**
- *
- * 假如是叶子节点,那么就执行相关操作。
- *
- * */
- else if(needDelNode.childNodes==null||needDelNode.childNodes.size()<=0){
- if(needDelNode.keys.size()>=_min){
- needDelNode.keys.remove(indexLoc);
- return true;
- }
- //---
- 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);
- }
- else if(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);
- }
- //右侧兄弟有多余的。
- else if(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);
- return true;
- }
- else if(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);
- return true;
- }
- else{
- return false;
- }
- }
- }
- return true;
- }
- private void 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);
- }
- }
- else if(parentNode.childNodes.size()>=3){
- if(childIndexLOC==0){
- rightBrother=parentNode.childNodes.get(1);
- }
- else if(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;
- }
- //--右边兄弟有余钱,那么就借
- else if(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);
- }
- for(TreeUnit iUnit:rightBrother.childNodes){
- currentUnit.childNodes.add(iUnit);
- iUnit._parent=currentUnit;
- }
- parentNode.keys.remove(keyIndexLOC);
- parentNode.childNodes.remove(keyIndexLOC+1);
- recursion_checkCombination(parentNode);
- return;
- }
- }
- }
- }