package org.riley.tree;
import java.util.Random;
/**
* 保存int的集合 集合中的元素存放在B-树中
*
* @author dou
*
*/
public class IntBalancedSet implements Cloneable
{
private static final int MINIMUM = 2;// 非根节点中最少存放的元素个数
private static final int MAXIMUM = 2 * MINIMUM;// 节点中最多存放的元素个数
int dataCount;// 存放节点中元素的个数
int[] data;
int childCount;// 存放节点中子树的个数
IntBalancedSet[] subset;
/**
* 为数组提供额外的空间,方便对数组进行删除和添加操作
*/
public IntBalancedSet()
{
data = new int[MAXIMUM + 1];
subset = new IntBalancedSet[MAXIMUM + 2];
}
/**
* 在集合中添加新元素
*
* @param element
*/
public void add(int element)
{
looseAdd(element);
/*
* 如果根节点比MAXIMUM大时,将根节点复制给一个新节点.并清空根节点.将新节点作为个根节点的 子树节点.再对此子节点进行拆分.
* B-数只在根节点处才能增加高度
*/
if (dataCount > MAXIMUM) {
IntBalancedSet cpy = copyData();
data = new int[MAXIMUM + 1];
dataCount = 0;
childCount = dataCount + 1;
subset = new IntBalancedSet[MAXIMUM + 2];
subset[0] = cpy;
fixExcess(0);
}
}
/**
* B-树是有效的的前提下,可以调用此方法. 如果elememt在集合中存在.那么集合不变.否则,该元素添加到集合中.并且集合的根节点元素
* 数目允许比MAXIMUM大1
*
* @param element
*/
private void looseAdd(int element)
{
int i = firstGE(element);
if (i == dataCount) {
if (childCount == 0) {
insertEle(element, i);
} else {
subset[i].looseAdd(element);
fixExcess(i);
}
} else {
if (data[i] == element) {
return;
} else {
if (childCount == 0) {
insertEle(element, i);
} else {
subset[i].looseAdd(element);
fixExcess(i);
}
}
}
}
/**
* 将element插入到locale位置.其后的元素往后移
*
* @param element
* @param locale
*/
private void insertEle(int element, int locale)
{
for (int i = dataCount; i > locale; i--) {
data[i] = data[i - 1];
}
data[locale] = element;
dataCount++;
// System.out.println(dataCount+" "+childCount);
}
/**
* 将subset[i]拆分为两个元素个数为MINIMUM,子树数目为MINIMUM+1的两个节点. 分别存放在set1,和set2
*
* @param set1
* @param set2
* @param i
*/
private void divoteSub(IntBalancedSet set1, IntBalancedSet set2, int i)
{
System.arraycopy(subset[i].data, 0, set1.data, 0, MINIMUM);
System.arraycopy(subset[i].subset, 0, set1.subset, 0, MINIMUM + 1);
System.arraycopy(subset[i].data, MINIMUM + 1, set2.data, 0, MINIMUM);
System.arraycopy(subset[i].subset, MINIMUM + 1, set2.subset, 0, MINIMUM + 1);
set1.dataCount = MINIMUM;
set1.childCount = subset[i].childCount / 2;
set2.dataCount = MINIMUM;
set2.childCount = subset[i].childCount / 2;
}
/**
* 调用此方法必须保证除了subset[i]有MAXIMUM+1个元素外,整棵B-树仍然有效的
* 将subset[i]拆分为两个元素个数为MINIMUM的节点.在将节点插入到根节点的i和i+1位置
*
* @param i
*/
private void fixExcess(int i)
{
if (subset[i].dataCount > MAXIMUM) {
IntBalancedSet set1 = new IntBalancedSet();
IntBalancedSet set2 = new IntBalancedSet();
insertEle(subset[i].data[MINIMUM], i);// 在父节点插入该中间元素.
divoteSub(set1, set2, i);
subset[i] = set1;
for (int j = childCount; j > i + 1; j--) {
subset[j] = subset[j - 1];
}
subset[i + 1] = set2;
childCount++;
// System.out.println(data[0]);
}
}
/**
* 返回一个新的引用中的data和subset指向当前节点的data和subset;
*
* @return
*/
private IntBalancedSet copyData()
{
IntBalancedSet copy;
copy = new IntBalancedSet();
copy.data = data;
copy.dataCount = dataCount;
copy.childCount = childCount;
copy.subset = subset;
return copy;
}
@Override
public Object clone()
{
IntBalancedSet copy;
copy = new IntBalancedSet();
copy.data = data.clone();
copy.dataCount = dataCount;
copy.childCount = childCount;
copy.subset = subset.clone();
return copy;
}
/**
* 在B-树中查找target.
*
* @param target
* @return
*/
public boolean contains(int target)
{
int i = firstGE(target);
// System.out.println("i:"+i);
if (i == dataCount) {
if (childCount == 0)
return false;
else
return subset[i].contains(target);
}
else {
if (target == data[i]) {
return true;
}
else {
if (childCount == 0)
return false;
else
return subset[i].contains(target);
}
}
}
/**
* 返回根节点中第一个大于或等于target的元素的位置 如果没有这样的元素,则返回dataCount
*
* @param target
* @return
*/
private int firstGE(int target)
{
int i = 0;
for (; i < dataCount; i++) {
if (data[i] >= target)
return i;
}
return i;
}
/**
* 在集合中删除元素
*
* @param target
* @return
*/
public boolean remove(int target)
{
boolean answer = looseRemove(target);
/**
* 如果根节点没有元素,并且仅有一个子节点.那么删除子节点
*/
if ((dataCount == 0) && (childCount == 1)) {
dataCount = subset[0].dataCount;
childCount = subset[0].childCount;
data = subset[0].data;
subset = subset[0].subset;
}
return answer;
}
/**
* 如果target在集合中,将他删除并返回true.否则返回false 执行该方法后根节点的元素数目可能比MINIMUM小1
*
* @param target
* @return
*/
private boolean looseRemove(int target)
{
int i = firstGE(target);
if (childCount == 0) {
if (i != dataCount && data[i] == target) {
// 在data[i]中找到元素.并且没有子节点
cover(i);
return true;
} else {
return false;
}
} else {
if (i != dataCount && data[i] == target) {
/**
* 在data[i]中找到元素.但有子节点.将子节点中的最大元素覆盖i.既在所有比 data[i]小的元素集合中的最大值.
* subset[i]的元素数目能比最小值小1
*/
data[i] = subset[i].removeBiggest();
if (subset[i].dataCount < MINIMUM)
fixShortage(i);
return true;
} else {
/**
* 在data[i]中找不到元素.但有子节点.递归调用子节点的该方法.
*/
boolean answer = subset[i].looseRemove(target);
if (subset[i].dataCount < MINIMUM)
fixShortage(i);
return answer;
}
}
}
/**
* 当subset[i]只有MINIMUM-1个元素时调用此方法 该方法使根节点的元素个数比MINIMU小1
*
* @param i
*/
private void fixShortage(int i)
{
if (i != 0 && subset[i - 1].dataCount > MINIMUM) {
/**
* 如果subset[i-1]的元素数目比MINIMUM大.那么将data[i-1]的值插入到subset[i]
* 的data[0]位置.再将subset[i-1]的最后个元素转移到data[i-1]的位置.如果subset[i-1]
* 有子树那么将subset[i-1]的最大子树添加到subset[i]的subset[0]位置.
*/
subset[i].insertEle(data[i - 1], 0);
data[i - 1] = subset[i - 1].cover(subset[i - 1].dataCount - 1);
if (subset[i - 1].childCount != 0) {
subset[i].addSubset(subset[i - 1].coverSub(subset[i - 1].childCount - 1), 0);
}
return;
}
if (i != 0 && subset[i - 1].dataCount == MINIMUM) {
subset[i - 1].insertEle(data[i - 1], subset[i - 1].dataCount);
cover(i - 1);
combineSub(subset[i - 1], subset[i]);
coverSub(i);
return;
}
if (i < dataCount && subset[i + 1].dataCount > MINIMUM) {
subset[i].insertEle(data[i], subset[i].dataCount);
data[i] = subset[i + 1].cover(0);
if (subset[i + 1].childCount != 0) {
subset[i].addSubset(subset[i + 1].coverSub(0),
subset[i].childCount);
}
return;
}
if (i < dataCount && subset[i + 1].dataCount == MINIMUM) {
subset[i + 1].insertEle(data[i], 0);
cover(i);
combineSub(subset[i], subset[i + 1]);
coverSub(i + 1);
return;
}
}
private int removeBiggest()
{
if (childCount == 0) {
return data[--dataCount];
} else {
int answer = subset[childCount - 1].removeBiggest();
if (subset[childCount - 1].dataCount < MINIMUM) {
fixShortage(childCount - 1);
}
return answer;
}
}
/**
* 将set2的元素和孩子节点添加到set1的后面;保证set1+set2的元素和不大于MAXIMUM
*
* @param set1
* @param set2
*/
private void combineSub(IntBalancedSet set1, IntBalancedSet set2) {
for (int i = 0; i < set2.dataCount; i++) {
// System.out.println(" combineSub "+set1.dataCount+" "+set2.dataCount);
set1.data[set1.dataCount++] = set2.data[i];
}
for (int i = 0; i < set2.childCount; i++) {
set1.subset[set1.childCount++] = set2.subset[i];
}
}
/**
* 删除节点中i位置的子节点.其后的子节点往前移动一个位置.
*
* @param i
*/
private IntBalancedSet coverSub(int i)
{
IntBalancedSet answer = subset[i];
for (int j = i; j < childCount; j++) {
subset[j] = subset[j + 1];
}
childCount--;
return answer;
}
/**
* 删除节点中i位置的元素.其后的元素往前移动一个位置.
*
* @param i
*/
private int cover(int i) {
int answer = data[i];
for (int j = i; j < dataCount; j++) {
data[j] = data[j + 1];
}
dataCount--;
return answer;
}
// private void tranferEle(int i,int flag){
// int dl=i+(flag==-1?0:flag);//datalocation
// subset[i].insertEle(data[dl], 0);
// data[dl]=subset[i+flag].data];
// if(subset[i-1].childCount!=0){
// subset[i-1].addSubset(subset[subset[i-1].childCount--],0);
// }
// }
/**
* 调用该方法的节点必须保证其子节点的数目比B-树要求的少一 调用后将sub添加到l位置.原本l后的节点往后移一个位置
*
* @param sub
* @param l
*/
private void addSubset(IntBalancedSet sub, int l)
{
for (int i = childCount; i > l; i--) {
subset[i] = subset[i - 1];
}
subset[l] = sub;
childCount++;
}
// private int removeLastest(){
//
// }
public void print(int indent)
{
final int EXTRA_INDENTATION = 4;
int i;
int space;
for (space = 0; space < indent; space++) {
System.out.print(" ");
}
for (i = 0; i < dataCount; i++) {
System.out.print(data[i] + ",");
}
System.out.print("DC:" + dataCount + " CC:" + childCount);
System.out.println();
for (i = childCount - 1; i >= 0; i--) {
subset[i].print(indent + EXTRA_INDENTATION);
}
}
public static void main(String[] args)
{
IntBalancedSet set = new IntBalancedSet();
Random rg = new Random();
for (int i = 0; i < 2000; i++) {
int num = rg.nextInt(10000);
System.out.println("Adding " + num);
set.add(num);
// System.out.println("tree so far:");
// set.print(4);
}
System.out.println("final version of tree");
set.print(4);
int num = rg.nextInt(10000);
if (set.contains(num))
System.out.println("found it!");
else
System.out.println("all that time, and nothing to show for it!");
}
}