B-Tree的查找、插入和删除(java实现)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_37885641/article/details/83721223

一、java Bean

package com.hgldp.web.pojo;

import java.util.LinkedList;

/**
 * @author hgl
 * @data 2018年11月3日
 * @description b-tree 结点
 */
public class BSTNode {

	/*
	 * 关键字数量
	 */
	private int keynum;
	
	/*
	 * 关键字集合
	 */
	private LinkedList<Integer> keys;
	
	/*
	 * 孩子结点的集合
	 */
	private LinkedList<BSTNode> childs;
	
	/*
	 * 父结点
	 */
	private BSTNode parent;

	public int getKeynum() {
		return keynum;
	}

	public void setKeynum(int keynum) {
		this.keynum = keynum;
	}

	public LinkedList<Integer> getKeys() {
		return keys;
	}

	public void setKeys(LinkedList<Integer> keys) {
		this.keys = keys;
	}

	public LinkedList<BSTNode> getChilds() {
		return childs;
	}

	public void setChilds(LinkedList<BSTNode> childs) {
		this.childs = childs;
	}

	public BSTNode getParent() {
		return parent;
	}

	public void setParent(BSTNode parent) {
		this.parent = parent;
	}

	@Override
	public String toString() {
		return "BSTNode [keynum=" + keynum + ", keys=" + keys + ", childs=" + childs + ", parent=" + parent + "]";
	}
}

package com.hgldp.web.pojo;

/**
 * @author hgl
 * @data 2018年11月3日
 * @description 查找的结果
 */
public class Result {

	/*
	 * 查找到的结点(如果未找到就是可以插入到的结点)
	 */
	private BSTNode ptr;
	
	/*
	 * 查找到的在集合中的位置(如果未找到即为可以插入的位置)
	 */
	private int i;
	
	/*
	 * 查找的结果的标志
	 * false 未找到
	 * true 找到
	 */
	private boolean tag;
	
	public Result(BSTNode ptr, int i, boolean tag) {
		this.ptr = ptr;
		this.i = i;
		this.tag = tag;
	}

	public BSTNode getPtr() {
		return ptr;
	}

	public void setPtr(BSTNode ptr) {
		this.ptr = ptr;
	}

	public int getI() {
		return i;
	}

	public void setI(int i) {
		this.i = i;
	}

	public boolean isTag() {
		return tag;
	}

	public void setTag(boolean tag) {
		this.tag = tag;
	}

	@Override
	public String toString() {
		return "Result [ptr=" + ptr + ", i=" + i + ", tag=" + tag + "]";
	}
}

二、B-Tree

/**
 * @author hgl
 * @data 2018年11月3日
 * @description b-tree 树
 */
public class BTree {

	/*
	 * b-tree的介
	 */
	private int degree;
	
	/*
	 * b-tree的根结点
	 */
	private BSTNode root;
	
	
	public int getDegree() {
		return degree;
	}


	public void setDegree(int degree) {
		this.degree = degree;
	}


	public BSTNode getRoot() {
		return root;
	}


	public void setRoot(BSTNode root) {
		this.root = root;
	}


	public BTree(int degree,BSTNode root) {
		this.degree = degree;
		this.root = root;
	}


	/**
	 * Result
	 * @param T 待查找的结点
	 * @param key 待查找的关键字
	 * @return
	 * description:搜索b-tree
	 */
	private Result searchTree(BSTNode T,int key){
		BSTNode p = T,q = null;
		boolean found = false;
		int i = 0;
		while(p !=null && !found){
			i = search(p,key);
			if(i>=0 && p.getKeys().get(i) == key){
				found = true;
			}else{
				q = p;
				p = p.getChilds().get(i);
			}
		}
		
		if(found){
			return new Result(p,i,true);
		}
		return new Result(q,i,false);//如果没找到,就返回可以插入的结点及位置
	}

	
	public boolean insertKey(int key){
		Result result = searchTree(root,key);
		if(!result.isTag()){
			return insertBTree(key, result.getPtr(), result.getI());
		}
		return false;
	}
	
	/**
	 * int
	 * @param p 待查找的结点
	 * @param key 待查找的关键字
	 * @return
	 * description:查找
	 */
	private int search(BSTNode p, int key) {
		for(int i = 1;i<=p.getKeynum();i++){
			if(p.getKeys().get(i)>key){
				return i-1;
			}else if(p.getKeys().get(i)== key){
				return i;
			}
		}
		return p.getKeynum();
	}
	
	/**
	 * boolean
	 * @param key 关键字
	 * @param q 待插入的结点
	 * @param i 插入的位置
	 * @return
	 * description:
	 */
	public boolean insertBTree(int key,BSTNode q,int i){
		int x = key,s;
		BSTNode ap = null,tmp = null;
		boolean finished = false;
		while(q !=null && !finished){
			insert(q,i,x,ap);
			if(q.getKeynum() < degree){
				finished = true;
			}else{
				s = degree%2 == 0?degree/2 : (degree/2+1);
				x = q.getKeys().get(s);
				ap = new BSTNode();
				split(q,s,ap);
				tmp = q;
				q = q.getParent();
				if(q!=null){
					i = search(q, x);
				}
			}
		}
		
		if(!finished){
			root = tmp;
			newRoot(q,x,ap);//当BTree是空树或根结点已经分裂未结点q和ap
		}
		return false;
	}


	/**
	 * void
	 * @param q
	 * @param x
	 * @param ap
	 * description:更新根结点
	 */
	private void newRoot(BSTNode q, int x, BSTNode ap) {
		q = new BSTNode();
		q.setChilds(new LinkedList<BSTNode>());
		q.setKeys(new LinkedList<Integer>());
		q.setKeynum(1);
		q.setParent(null);
		q.getKeys().add(-1);
		q.getChilds().add(root);
		q.getKeys().add(x);
		q.getChilds().add(ap);
        for(int i =0;i<=q.getKeynum();i++){
        	   if(q.getChilds().get(i) != null){
        		   q.getChilds().get(i).setParent(q);
        		   
        		 }
        }
		root = q;
	}


	/**
	 * void
	 * @param q
	 * @param s
	 * @param ap
	 * description:分裂结点
	 */
	private void split(BSTNode q, int s, BSTNode ap) {

		ap.setChilds(new LinkedList<BSTNode>());
		ap.setKeys(new LinkedList<Integer>());
		ap.getKeys().add(-1);//0号位置不占用
		ap.getChilds().add(q.getChilds().get(s));
		ap.getChilds().addAll(q.getChilds().subList(s+1, degree+1));
		ap.getKeys().addAll(q.getKeys().subList(s+1, degree+1));
		ap.setKeynum(degree-s);
		q.setKeynum(s-1);
		for(int i = degree;i>q.getKeynum();i--){
			q.getChilds().removeLast();
			q.getKeys().removeLast();
		}
		for(int i = 0;i<=ap.getKeynum();i++){
			if(ap.getChilds().get(i)!=null){
				ap.getChilds().get(i).setParent(ap);
			}
		}
	}


	/**
	 * void
	 * @param q
	 * @param i
	 * @param x
	 * @param ap
	 * description:插入关键字
	 */
	private void insert(BSTNode q, int i, int x, BSTNode ap) {

		q.getChilds().add(i+1, ap);
		q.getKeys().add(i+1,x);
		if(ap != null){
			ap.setParent(q);
		}
		q.setKeynum(q.getKeynum()+1);
	}

	/**
	 * boolean
	 * @param bt
	 * @param key
	 * @return
	 * description:删除关键字
	 */
	public boolean deleteKey(int key){
		//先查找树中是否有关键字
		Result result = searchTree(root, key);
		if(result.isTag()){
			return deleteTree(result);
		}else{
			return false;
		}
	}
	
	public boolean deleteTree(Result result){ 
		/*
		 *  若删除关键字未非终端结点中的Ki,则可以指针Ai所指子树中的最小关键字
		 *  Y代替Ki
		 */
		BSTNode q = result.getPtr();
		Result minResult = null;
		int i= 0;
		BSTNode node = null;
		if(q.getChilds().get(result.getI()) != null){
			minResult = searchMinKey(q.getChilds().get(result.getI())); // 所以,delete()方法删除的都是终端结点
		}
		if(minResult != null){
			node = minResult.getPtr();
			i = minResult.getI();
		}else{
			node = result.getPtr();
			i = result.getI();
		}
		// tmpKeys存储的是整个keys,当node和q的指向是同一个对象的时候,会发生异常
		LinkedList<Integer> tmpKeys = new LinkedList<Integer>();
        tmpKeys.addAll(node.getKeys());
		q.getKeys().remove(result.getI());
		q.getKeys().add(result.getI(),tmpKeys.get(i));
		return delete(node,i);
	}
	
	/**
	 * boolean
	 * @param q 待删关键字的结点
	 * @param i 待删关键字的位置
	 * @return
	 * description: 
	 */
	public boolean delete(BSTNode q,int i){
		int s,tag = 0;
		BSTNode p = null,lc,rc; // p 会指向q的父节点
		s = degree%2 == 0 ? degree/2 : (degree/2+1);
		int order = -1;
		//p = foundParent(q,p,order);
		p = q.getParent();
        if(p == null){ //根结点
        	   tag = 1;
        }else{
        	   order = foundIndexOfParent(q,p);
        	   if(q.getKeynum() >= s){
        		   tag = 2; //直接删除结点
        	   }else{ 
        		   if(tag == 0 && order < p.getKeynum() && p.getChilds().get(order+1).getKeynum() >= s){
        			   //右兄弟结点关键字个数大于s
        			   tag = 3;
        		   }
        		   if(tag == 0 && order > 0 && p.getChilds().get(order-1).getKeynum() >= s){
        			   //左兄弟结点关键字个数大于s
        			   tag = 4;
        		   }
        		   if(tag == 0 && order < p.getKeynum() && p.getChilds().get(order+1).getKeynum() == s -1){
        			   //右兄弟结点关键字个数等于s-1
        			   tag = 5;
        		   }
        		   if(tag == 0 && order > 0 && p.getChilds().get(order-1).getKeynum() == s - 1){
        			   //左兄弟结点关键字个数等于s -1
        			   tag  = 6;
        		   }
        	   }
        }
        
        switch(tag){
        case 0 : return false;
        case 1 : //只有根结点一个结点的情况
        	       removeKeyAndChild(q,i);
             	if(q.getKeynum() == 1 && i == 1){
        		       root = q.getChilds().get(0);
        	          }
             	q.setKeynum(q.getKeynum() - 1);
             	break;
        case 2 :
               removeKeyAndChild(q,i);
        	       q.setKeynum(q.getKeynum()-1);
        	       break;
        case 3 : 
        	       rc = p.getChilds().get(order+1);
        	       removeKeyAndChild(q, i);
        	       q.getKeys().add(p.getKeys().get(order+1));
        	       q.getChilds().add(rc.getChilds().get(0));
        	       p.getKeys().remove(order+1);
        	       p.getKeys().add(order+1,rc.getKeys().get(1));
        	       rc.getChilds().remove(0);
        	       rc.getKeys().remove(1);
        	       rc.setKeynum(rc.getKeynum() -1);
        	       break;
        case 4 :
        	       lc = p.getChilds().get(order - 1);
        	       removeKeyAndChild(q, i);
        	       q.getChilds().add(0,lc.getChilds().get(lc.getKeynum()));
        	       q.getKeys().add(1,p.getKeys().get(order));
        	       p.getKeys().remove(order);
        	       p.getKeys().add(order,lc.getKeys().get(lc.getKeynum()));
        	       removeKeyAndChild(lc, lc.getKeynum());
        	       lc.setKeynum(lc.getKeynum() - 1);
        	       break;
        case 5 :
        	       rc = p.getChilds().get(order + 1);
        	       removeKeyAndChild(q, i);
        	       q.getKeys().add(p.getKeys().get(order + 1));
        	       q.setKeynum(q.getKeynum() + rc.getKeynum());
        	       removeKeyAndChild(p, order+1); // p.getChilds(order) 指向 q,q和rc合并来,所以没有问题
        	       q.getChilds().addAll(rc.getChilds());
        	       q.getKeys().addAll(rc.getKeys().subList(1, rc.getKeys().size()));
        	       p.setKeynum(p.getKeynum() - 1);
        	       if(p.getKeynum() < s - 1){ //构造一个虚假关键字
        	    	      p.setKeynum(p.getKeynum() + 1);
        	    	      q = p;
        	    	      delete(q,q.getKeynum());
        	       }
        	       break;
        case 6 :
        	       lc = p.getChilds().get(order - 1);
        	       lc.getKeys().add(p.getKeys().get(order));
        	       lc.setKeynum(lc.getKeynum() + 1);
        	       removeKeyAndChild(q, i);
        	       q.setKeynum(q.getKeynum() - 1);
        	       removeKeyAndChild(p, order);
        	       p.setKeynum(p.getKeynum() - 1);
        	       lc.getChilds().addAll(q.getChilds());
        	       q.getKeys().removeFirst();
        	       lc.getKeys().addAll(q.getKeys());
        	       lc.setKeynum(lc.getKeynum() + q.getKeynum());
        	       if(p.getKeynum() < s - 1){
        	    	       p.setKeynum(p.getKeynum() + 1);
        	    	       q = p;
        	    	       delete(q,q.getKeynum());
        	       }
        	       break;
        }
        return true;
	}
	
	public void removeKeyAndChild(BSTNode q,int i){
		if(i > q.getKeys().size()-1){
			return ;
		}
		q.getChilds().remove(i);
		q.getKeys().remove(i);
	}
	public int foundIndexOfParent(BSTNode q,BSTNode p){
		int count;
		for(count = 0 ;p.getChilds().get(count)!=q;count ++);
	    return count;
	}
	/**
	 * Result
	 * @param p
	 * @return
	 * description:查找最小的结点
	 */
	public Result searchMinKey(BSTNode p){
		while(p!=null && p.getChilds().get(0)!=null){
			p = p.getChilds().get(0);
		}
		return new Result(p, 1, true);
	}
	//--------------------------------------------
	/*
	 * 打印b-tree树
	 */
	public void printfTree(BSTNode root,int count){
		count ++;
		for(int i = 0;i<=root.getKeynum();i++){
			if(i == 0){
				System.out.println(root.getKeys().toString());
			}
			if(root.getChilds().get(i) != null){
				System.out.print("第"+count+"层第"+i+"个孩子:");
				printfTree(root.getChilds().get(i),count);
			}
		}
	}

	@Override
	public String toString() {
		return "BTree [degree=" + degree + ", root=" + root + "]";
	}
}

三、测试类

public class Test {

	public static void main(String[] args) {
		BTree b = new BTree(3,null); //3阶树
		b.insertKey(12);
		b.insertKey(24);
		b.insertKey(37);
		b.insertKey(3);
		b.insertKey(45);
		b.insertKey(50);
		System.out.println("删除前:");
		b.printfTree(b.getRoot(),0);
		b.deleteKey(37);
		System.out.println("删除后:");
		b.printfTree(b.getRoot(), 0);
	}
}

四、打印的结果

删除前:
[-1, 24, 45]
第1层第0个孩子:[-1, 3, 12]
第1层第1个孩子:[-1, 37]
第1层第2个孩子:[-1, 50]
删除后:
[-1, 12, 45]
第1层第0个孩子:[-1, 3]
第1层第1个孩子:[-1, 24]
第1层第2个孩子:[-1, 50]
(注:-1可以忽略,因为keys的0号存储单元不使用,-1没有实际意义)

猜你喜欢

转载自blog.csdn.net/weixin_37885641/article/details/83721223