B-树Java实现

package BTree;

import java.util.Queue;
import java.util.LinkedList;

/*
 * 存储节点数据的Node类,关键字存储在key[1]key至[keynum],子节点指针存储在child[0]至child[keynum]
 * */
class Node {
	public static final int M = 3;

	public Node parent;

	public int keynum;
	int[] key;
	Node[] child;

	public Node() {
		parent = null;
		keynum = 0;
		key = new int[M + 1];
		child = new Node[M + 1];
	}
}
/*
 * 该类存储查询结果,tag为true时表示找到关键字,node为所在节点,pos为所在位置,1,2,,,keynum
 * tag为false时表示未找到关键字,node为应该插入的叶节点,pos为插入位置
 * */
class Result {
	boolean tag;
	Node node;
	int pos;

	public Result() {
	}

	public Result(Node node, int pos, boolean tag) {
		this.node = node;
		this.pos = pos;
		this.tag = tag;
	}
}

/*
 * 该类在删除关键字的方法中用到,用以保存关键字个数大于【m/2】-1的左兄弟或者右兄弟,node为空时表示
 * 没有符合要求的左兄弟或者右兄弟,不为空时tag指示左兄弟或者又兄弟,0左1右。
 * */
class Brother {
	Node node;
	int tag;

	public Brother(Node brother, int tag) {
		node = brother;
		this.tag = tag;
	}
}

/*
 * 存储合并两个节点后的结果。tag为true表示有分裂,key为中间关键字,否则合并无分裂。
 * */
class CombineResult {
	boolean tag;
	int key;

	public CombineResult(boolean b, int n) {
		tag = b;
		key = n;
	}
}

public class BTree {
	public Node bTree = new Node();
	/*
	 * 左中右顺序遍历
	 * */
	private void scanTree(Node bTree) {
		if (bTree != null) {
			for (int i = 1; i <= bTree.keynum; i++) {
				scanTree(bTree.child[i - 1]);
				System.out.println(bTree.key[i]);
			}
			scanTree(bTree.child[bTree.keynum]);
		}
	}
	/*
	 * 层次遍历
	 * */
	private void broadScan(Node bTree) {
		Queue<Node> tree = new LinkedList<Node>();
		tree.offer(bTree);
		Node node;
		while ((node = tree.poll()) != null) {
			for (int i = 1; i <= node.keynum; i++) {
				tree.offer(node.child[i - 1]);
				System.out.print(node.key[i] + " ");
			}
			tree.offer(node.child[node.keynum]);
			System.out.print(":");
			System.out.println(node.keynum);
		}
	}

	public void scan() {
		scanTree(bTree);
		broadScan(bTree);
	}
	/*
	 * 返回查询结果
	 * */
	public Result search(Node bTree, int key) {
		int i;
		for (i = 1; i <= bTree.keynum; i++) {
			if (bTree.key[i] == key) {
				break;
			}
		}
		if (i != bTree.keynum + 1) {
			return (new Result(bTree, i, true));
		} else {
			int j = 1;
			while (key > bTree.key[j] && j <= bTree.keynum) {
				j++;
			}
			if (j == bTree.keynum + 1) {
				if (bTree.child[bTree.keynum] != null) {
					return (search(bTree.child[bTree.keynum], key));
				} else {
					return (new Result(bTree, bTree.keynum + 1, false));
				}
			} else {
				if (bTree.child[j - 1] != null) {
					return (search(bTree.child[j - 1], key));
				} else {
					return (new Result(bTree, j, false));
				}
			}
		}
	}

	public boolean insertKey(int key) {
		Result res = search(this.bTree, key);
		if (res.tag) {
			return false;
		}
		return insert(this, res.node, key, null, res.pos);
	}
	
	/*
	 * 合并两个节点,若合并后无分裂,则lchild保存合并后的节点,否则lchild和rchild分别保存分裂后的
	 * 两个节点,返回值中的key属性保存中间的关键字,此方法包含递归
	 * */
	private CombineResult combine(Node lchild, Node rchild) {
		if (lchild.child[lchild.keynum] == null && rchild.child[0] == null) {
			int lnum = lchild.keynum, rnum = rchild.keynum;
			int total = lnum + rnum;
			if (total < Node.M) {
				for (int i = lnum + 1; i <= total; i++) {
					lchild.key[i] = rchild.key[i - lnum];
				}
				lchild.keynum = total;
				CombineResult cres = new CombineResult(false, 0);
				return cres;
			} else {
				int mid = total % 2 == 1 ? total / 2 + 1 : total / 2;
				int[] temp = new int[total + 1];
				for (int i = 1; i <= lnum; i++) {
					temp[i] = lchild.key[i];
				}
				for (int i = 1; i <= rnum; i++) {
					temp[i + lnum] = rchild.key[i];
				}
				for (int i = 1; i <= mid - 1; i++) {
					lchild.key[i] = temp[i];
				}
				for (int i = mid + 1; i <= total; i++) {
					rchild.key[i - mid] = temp[i];
				}
				lchild.keynum = mid - 1;
				rchild.keynum = total - mid;
				CombineResult cres = new CombineResult(true, temp[mid]);
				return cres;
			}
		} else if (lchild.child[lchild.keynum] != null
				&& rchild.child[0] != null) {
			CombineResult result = combine(lchild.child[lchild.keynum],
					rchild.child[0]);

			if (result.tag) {
				int lnum = lchild.keynum, rnum = rchild.keynum;
				int total = lnum + 1 + rnum;
				int mid = total % 2 == 1 ? total / 2 + 1 : total / 2;
				if (lnum + 1 + rnum < Node.M) {
					lchild.key[lnum + 1] = result.key;
					for (int i = 1; i <= rnum; i++) {
						lchild.key[lnum + 1 + i] = rchild.key[i];
					}
					for (int i = 0; i <= rnum; i++) {
						lchild.child[lnum + i] = rchild.child[i];
						if(lchild.child[lnum+i]!=null){
							lchild.child[lnum+i].parent=lchild;
						}
					}
					lchild.keynum = lnum + 1 + rnum;
					CombineResult cres = new CombineResult(false, 0);
					return cres;
				} else {
					int[] temp = new int[total + 1];
					Node[] ntemp = new Node[total + 1];
					for (int i = 1; i <= lnum; i++) {
						temp[i] = lchild.key[i];
					}
					temp[lnum + 1] = result.key;
					for (int i = 1; i <= rnum; i++) {
						temp[i + lnum + 1] = rchild.key[i];
					}
					for (int i = 0; i <= lnum; i++) {
						ntemp[i] = lchild.child[i];
					}
					for (int i = 0; i <= rnum; i++) {
						ntemp[i + 1 + lnum] = rchild.child[i];
					}
					for (int i = 1; i <= mid - 1; i++) {
						lchild.key[i] = temp[i];
					}
					for (int i = mid + 1; i <= total; i++) {
						rchild.key[i - mid] = temp[i];
					}
					for (int i = 0; i <= mid - 1; i++) {
						lchild.child[i] = ntemp[i];
						if(lchild.child[i]!=null){
							lchild.child[i].parent=lchild;
						}
					}
					for (int i = mid; i <= total + 1; i++) {
						rchild.child[i - mid] = ntemp[i];
						if(rchild.child[i-mid]!=null){
							rchild.child[i-mid].parent=rchild;
						}
					}
					lchild.keynum = mid - 1;
					rchild.keynum = total - mid;
					CombineResult cres = new CombineResult(true, temp[mid]);
					return cres;
				}
			} else {
				int lnum = lchild.keynum, rnum = rchild.keynum;
				int total = lnum + rnum;
				if (total < Node.M) {
					for (int i = lnum + 1; i <= total; i++) {
						lchild.key[i] = rchild.key[i - lnum];
						lchild.child[i] = rchild.child[i - lnum];
						if(lchild.child[i]!=null){
							lchild.child[i].parent=lchild;
						}
					}
					lchild.keynum = total;
					CombineResult cres = new CombineResult(false, 0);
					return cres;
				} else {
					int mid = total % 2 == 1 ? total / 2 + 1 : total / 2;
					int[] temp = new int[total + 1];
					Node[] ntemp = new Node[total + 1];
					for (int i = 1; i <= lnum; i++) {
						temp[i] = lchild.key[i];
					}
					for (int i = 0; i <= lnum; i++) {
						ntemp[i] = lchild.child[i];
					}
					for (int i = 1; i <= rnum; i++) {
						temp[i + lnum] = rchild.key[i];
						ntemp[i + lnum] = rchild.child[i];
					}
					for (int i = 1; i <= mid - 1; i++) {
						lchild.key[i] = temp[i];
					}
					for (int i = 0; i <= mid - 1; i++) {
						lchild.child[i] = ntemp[i];
						if(lchild.child[i]!=null){
							lchild.child[i].parent=lchild;
						}
					}
					for (int i = mid; i <= total; i++) {
						rchild.child[i - mid] = ntemp[i];
						if(rchild.child[i-mid]!=null){
							rchild.child[i-mid].parent=rchild;
						}
					}
					for (int i = mid + 1; i <= total; i++) {
						rchild.key[i - mid] = temp[i];
					}
					lchild.keynum = mid - 1;
					rchild.keynum = total - mid;
					CombineResult cres = new CombineResult(true, temp[mid]);
					return cres;
				}
			}
		} else if (lchild.child[lchild.keynum] != null
				&& rchild.child[0] == null) {
			int lnum = lchild.keynum, rnum = rchild.keynum;
			int total = lnum + rnum;
			if (total < Node.M) {
				for (int i = lnum + 1; i <= total; i++) {
					lchild.key[i] = rchild.key[i - lnum];
					lchild.child[i] = rchild.child[i - lnum];
					if(lchild.child[i]!=null){
						lchild.child[i].parent=lchild;
					}
				}
				lchild.keynum = total;
				CombineResult cres = new CombineResult(false, 0);
				return cres;
			} else {
				int mid = total % 2 == 1 ? total / 2 + 1 : total / 2;
				int[] temp = new int[total + 1];
				Node[] ntemp = new Node[total + 1];
				for (int i = 1; i <= lnum; i++) {
					temp[i] = lchild.key[i];
				}
				for (int i = 0; i <= lnum; i++) {
					ntemp[i] = lchild.child[i];
				}
				for (int i = 1; i <= rnum; i++) {
					temp[i + lnum] = rchild.key[i];
					ntemp[i + lnum] = rchild.child[i];
				}
				for (int i = 1; i <= mid - 1; i++) {
					lchild.key[i] = temp[i];
				}
				for (int i = 0; i <= mid - 1; i++) {
					lchild.child[i] = ntemp[i];
					if(lchild.child[i]!=null){
						lchild.child[i].parent=lchild;
					}
				}
				for (int i = mid; i <= total; i++) {
					rchild.child[i - mid] = ntemp[i];
					if(rchild.child[i-mid]!=null){
						rchild.child[i-mid].parent=rchild;
					}
				}
				for (int i = mid + 1; i <= total; i++) {
					rchild.key[i - mid] = temp[i];
				}
				lchild.keynum = mid - 1;
				rchild.keynum = total - mid;
				CombineResult cres = new CombineResult(true, temp[mid]);
				return cres;
			}
		} else if (lchild.child[lchild.keynum] == null
				&& rchild.child[0] != null){
			lchild.child[lchild.keynum] = rchild.child[0];
			if(lchild.child[lchild.keynum]!=null){
				lchild.child[lchild.keynum].parent=lchild;
			}
			int lnum = lchild.keynum, rnum = rchild.keynum;
			int total = lnum + rnum;
			if (total < Node.M) {
				for (int i = lnum + 1; i <= total; i++) {
					lchild.key[i] = rchild.key[i - lnum];
					lchild.child[i] = rchild.child[i - lnum];
					if(lchild.child[i]!=null){
						lchild.child[i].parent=lchild;
					}
				}
				lchild.keynum = total;
				CombineResult cres = new CombineResult(false, 0);
				return cres;
			} else {
				int mid = total % 2 == 1 ? total / 2 + 1 : total / 2;
				int[] temp = new int[total + 1];
				Node[] ntemp = new Node[total + 1];
				for (int i = 1; i <= lnum; i++) {
					temp[i] = lchild.key[i];
				}
				for (int i = 0; i <= lnum; i++) {
					ntemp[i] = lchild.child[i];
				}
				for (int i = 1; i <= rnum; i++) {
					temp[i + lnum] = rchild.key[i];
					ntemp[i + lnum] = rchild.child[i];
				}
				for (int i = 1; i <= mid - 1; i++) {
					lchild.key[i] = temp[i];
				}
				for (int i = 0; i <= mid - 1; i++) {
					lchild.child[i] = ntemp[i];
					if(lchild.child[i]!=null){
						lchild.child[i].parent=lchild;
					}
				}
				for (int i = mid; i <= total; i++) {
					rchild.child[i - mid] = ntemp[i];
					if(rchild.child[i-mid]!=null){
						rchild.child[i-mid].parent=rchild;
					}
				}
				for (int i = mid + 1; i <= total; i++) {
					rchild.key[i - mid] = temp[i];
				}
				lchild.keynum = mid - 1;
				rchild.keynum = total - mid;
				CombineResult cres = new CombineResult(true, temp[mid]);
				return cres;
			}
		} else {
			return null;
		}
	}

	public boolean deleteKey(int key) {
		return delete(this, bTree, key);
	}
	/*
	 * 删除算法:1,先合并所删除关键字的左右节点,若合并后两关键分裂,则直接用分裂处的中间关键字填补所删除关键,删除完成
	 * 2,若左右节点合并后无分裂,则判断所删除关键字所在节点的剩余关键字个数,若大于等于【m/2】-1,则删除完成
	 * 3,若剩余关键字个数小于【m/2】-1,则首先找左右兄弟借节点,通过简单调整自己,父节点和兄弟节点的关系完成删除
	 * 4,若没有兄弟可借节点,则将父节点的关键字拉下一个,删除父节点中的该关键字,用到递归
	 * */
	private boolean delete(BTree tree,Node bTree, int key) {
		Result result = search(bTree, key);
		if (!result.tag) {
			return false;
		} else {
			CombineResult cr = combine(result.node.child[result.pos - 1],
					result.node.child[result.pos]);
			if (cr.tag) {//子节点合并后分裂为两个节点加一个关键字,用此关键字填补删除的关键字
				result.node.key[result.pos] = cr.key;
				return true;
			} else {
				for (int i = result.pos; i < result.node.keynum; i++) {
					result.node.key[i] = result.node.key[i + 1];
					result.node.child[i] = result.node.child[i + 1];
				}
				result.node.keynum--;

				// 关键字个数大于M/2-1
				int min = Node.M % 2 == 0 ? Node.M / 2 : Node.M / 2 + 1;
				if (result.node.keynum >= min - 1) {// 大于最小关键字个数,直接删除关键字
					return true;
				} else {
					if (result.node.parent == null) {//根节点的处理
						if(result.node.keynum>=1){
							return true;
						}else{
							tree.bTree=bTree.child[0];
							return true;
						}
					}
					int posInParent = posAtParent(result.node);
					Brother bro = getWealthyBrother(result.node);// 获取可以支援自己的兄弟节点
					if (bro.node != null) {
						if (bro.tag == 0) {// 左边的兄弟
							for (int k = result.node.keynum; k >= 1; k--) {
								result.node.key[k + 1] = result.node.key[k];
							}
							for (int k = result.node.keynum; k >= 0; k--) {
								result.node.key[k + 1] = result.node.key[k];
							}
							result.node.child[0] = bro.node.child[bro.node.keynum];
							if(result.node.child[0]!=null){
								result.node.child[0].parent=result.node;
							}
							result.node.key[1] = result.node.parent.key[posInParent];
							result.node.parent.key[posInParent] = bro.node.key[bro.node.keynum];
							result.node.keynum++;
							bro.node.keynum--;
							return true;
						} else {// 右边的兄弟
							result.node.key[result.node.keynum + 1] = result.node.parent.key[posInParent + 1];
							result.node.child[result.node.keynum + 1] = bro.node.child[0];
							if(result.node.child[result.node.keynum+1]!=null){
								result.node.child[result.node.keynum+1].parent=result.node;
							}
							result.node.parent.key[posInParent + 1] = bro.node.key[1];
							result.node.keynum++;
							for (int k = 1; k < bro.node.keynum; k++) {
								bro.node.key[k] = bro.node.key[k + 1];
							}
							for (int k = 0; k < bro.node.keynum; k++) {
								bro.node.child[k] = bro.node.child[k + 1];
							}
							bro.node.keynum--;
							return true;
						}
					} else {
						if (posInParent == result.node.parent.keynum) {
							for (int k = result.node.keynum; k >= 1; k--) {
								result.node.key[k + 1] = result.node.key[k];
							}
							result.node.key[1] = result.node.parent.key[result.node.parent.keynum];
							for (int k = result.node.keynum; k >= 0; k--) {
								result.node.child[k + 1] = result.node.child[k];
							}
							result.node.child[0] = null;
							result.node.keynum++;
							delete(tree,bTree, result.node.parent.key[posInParent]);
							return true;
						} else {
							result.node.key[result.node.keynum + 1] = result.node.parent.key[posInParent + 1];
							result.node.child[result.node.keynum + 1] = null;
							result.node.keynum++;
							delete(tree,bTree, result.node.parent.key[posInParent+1]);
							return true;
						}
					}
				}
			}
		}
	}
	/*
	 * 查找在父节点中的位置,即由父节点的child[?]所指向
	 * */
	public int posAtParent(Node node) {
		int mark = node.key[1];
		int j;
		for (j = 1; j <= node.parent.keynum; j++) {
			if (mark < node.parent.key[j]) {
				break;
			}
		}
		return j - 1;
	}
	/*
	 * 寻找能给自己借关键字的兄弟
	 * */
	public Brother getWealthyBrother(Node node) {
		Node brother = null;
		int tag;
		int min = Node.M % 2 == 0 ? Node.M / 2 : Node.M / 2 + 1;
		// 找出它在父亲节点中的位置
		int pos = posAtParent(node);
		if (pos == 0 && node.parent.child[1].keynum > min - 1) {
			brother = node.parent.child[1];
			tag = 1;
		} else if (pos == node.parent.keynum
				&& node.parent.child[node.parent.keynum - 1].keynum > min - 1) {
			brother = node.parent.child[node.parent.keynum - 1];
			tag = 0;
		} else if (node.parent.child[pos - 1].keynum > min - 1) {
			brother = node.parent.child[pos - 1];
			tag = 0;
		} else if (node.parent.child[pos + 1].keynum > min - 1) {
			brother = node.parent.child[pos + 1];
			tag = 1;
		} else {
			tag = -1;
		}
		return new Brother(brother, tag);
	}

	public boolean insert(BTree tree, Node base, int key, Node node, int pos) {
		// 插入
		int i;
		for (i = base.keynum; i >= pos; i--) {
			base.key[i + 1] = base.key[i];
			base.child[i + 1] = base.child[i];
		}
		base.key[i + 1] = key;
		base.child[i + 1] = node;
		if(node!=null){
			node.parent=base;
		}
		base.keynum++;
		// 判断分裂
		if (base.keynum == Node.M) {
			int mid = Node.M / 2;
			int splitPos = (Node.M % 2 == 1) ? mid + 1 : mid;
			// 创建新节点
			Node rNode = new Node();
			rNode.parent = base.parent;
			for (int j = splitPos + 1; j <= Node.M; j++) {
				rNode.key[j - splitPos] = base.key[j];
				rNode.child[j - splitPos] = base.child[j];
				if(rNode.child[j-splitPos]!=null){
					rNode.child[j-splitPos].parent=rNode;
				}
				
			}
			rNode.child[0] = base.child[splitPos];
			if(rNode.child[0]!=null){
				rNode.child[0].parent=rNode;
			}
			
			
			rNode.keynum = Node.M - splitPos;
			// 改造旧节点
			base.keynum = splitPos - 1;
			// 插入到上级节点
			if (base.parent == null) {
				base.parent = new Node();
				tree.bTree = base.parent;
				tree.bTree.key[1] = base.key[splitPos];
				tree.bTree.child[0] = base;
				tree.bTree.child[1] = rNode;
				rNode.parent = tree.bTree;
				tree.bTree.keynum = 1;
			} else {
				// Result sResult = search(tree.bTree, base.key[splitPos]);
				int posAtParent=posAtParent(base)+1;
				insert(tree, base.parent, base.key[splitPos], rNode,
						posAtParent);
			}
		}
		return true;

	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		BTree tree = new BTree();
		String[] dataList = args[0].split(",");
		int[] datas = new int[dataList.length];
		for (int i = 0; i < dataList.length; i++) {
			datas[i] = Integer.parseInt(dataList[i]);
			tree.insertKey(datas[i]);
		}
		tree.scan();
		tree.deleteKey(6);
		tree.scan();
	}

}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值