B-树

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!");
    }
}

 

posted @ 2012-12-09 16:03  rilley  阅读(336)  评论(0编辑  收藏  举报