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();
}
}