【算法】【算法】b树的实现(2)---java版代码

感觉上,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;
    				
    				
    			}
    			
    		}    		

    		

    		
    	
    }

  
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值