B+ tree的java实现

这个代码来自网址:http://bofang.iteye.com/blog/1387785
挺好用的,感谢!

import java.util.HashMap;
import java.util.Map;


/**
 * The simple implementation of B+-Tree, reference http://en.wikipedia.org/wiki/B%2B_tree
 * 
 * @author bo.fangbo
 *
 * @param <T>
 * @param <V>
 */
public class BPlusTree <T extends Comparable<T>, V> {

    /**
     * the branching factor of the tree, measuring the capacity of nodes.
     * 
     * a) the number of children for internal node must be in scope [ Math.ceil(factor/2), factor ].
     * b) the number of children for leaf node must be in scope [ Math.floor(factor/2), factor-1 ]
     */
    private int factor;

    private static final int DEFAULT_FACTOR = 5;

    private int MIN_CHILDREN_FOR_INTERNAL;
    private int MAX_CHILDREN_FOR_INTERNAL;
    private int MIN_FOR_LEAF;
    private int MAX_FOR_LEAF;

    private Node<T, V> root = null;

    public BPlusTree() {
        this(DEFAULT_FACTOR);
    }

    public BPlusTree(int factor) {
        this.factor = factor;

        this.MIN_CHILDREN_FOR_INTERNAL = Double.valueOf(Math.ceil(1.0 * this.factor / 2)).intValue();
        this.MAX_CHILDREN_FOR_INTERNAL = this.factor;
        this.MIN_FOR_LEAF = Double.valueOf(Math.floor(1.0 * this.factor / 2)).intValue();
        this.MAX_FOR_LEAF = this.factor - 1;

        this.root = new LeafNode<T, V>();
    }

    public void set(T key, V value) {
        if (key == null)    throw new NullPointerException("must not be null for key.");
        Node node = this.root.insert(key, value);

        if (node != null) this.root = node;
    }

    public V get(T key) {
        return this.root.get(key);
    }

    public int height() {
        int height = 1;
        Node node = this.root;
        while( !(node instanceof LeafNode)) {
            height++;
            node = ((InternalNode)node).pointers[0];
        }

        return height;
    }

    /**
     * the abstract node definition, define the operation of leaf node and internal node.
     * 
     * @author bo.fangbo
     *
     * @param <T>
     * @param <V>
     */
    abstract class Node<T extends Comparable<T>, V> {

        protected Node<T, V> parent;

        protected Object[] keys;

        protected int size;


        /**
         * if new parent node is created when insert the key-value, the created parent node is returned,
         * in other case, this method return null.
         * 
         * @param key
         * @param value
         * @return
         */
        abstract Node<T, V> insert(T key, V value);

        abstract V get(T key);
    }

    /**
     * the internal node which manages the pointers.
     * 
     * @author bo.fangbo
     *
     * @param <T>
     * @param <V>
     */
    class InternalNode<T extends Comparable<T>, V> extends Node<T, V> {
        private Node<T, V>[] pointers;

        public InternalNode() {
            this.size = 0;
            this.pointers = new Node[MAX_CHILDREN_FOR_INTERNAL + 1];
            this.keys = new Object[MAX_CHILDREN_FOR_INTERNAL];
        }

        public Node<T, V> insert(T key, V value) {
            int i = 0;
            for (; i < this.size; i++) {
                if ( key.compareTo( (T)this.keys[i] ) < 0 )  break;
            }

            return this.pointers[i].insert(key, value);
        }

        public V get(T key) {
            int i = 0;
            for (; i < this.size; i++) {
                if ( key.compareTo( (T)this.keys[i] ) < 0)  break;
            }

            return this.pointers[i].get(key);
        }

        /**
         * 
         * @param key
         * @param leftChild
         * @param rightChild
         * @return
         */
        private Node<T, V> insert(T key, Node<T, V> leftChild, Node<T, V> rightChild){
            if (this.size == 0) {
                this.size++;
                this.pointers[0] = leftChild;
                this.pointers[1] = rightChild;
                this.keys[0] = key;

                leftChild.parent = this;
                rightChild.parent = this;

                return this;
            }

            Object[] newKeys = new Object[MAX_CHILDREN_FOR_INTERNAL + 1];
            Node[] newPointers = new Node[MAX_CHILDREN_FOR_INTERNAL + 2];

            int i = 0;
            for(; i < this.size; i++) {
                T curKey = (T)this.keys[i];
                if (curKey.compareTo(key) > 0) break;
            }

            System.arraycopy(this.keys, 0, newKeys, 0, i);
            newKeys[i] = key;
            System.arraycopy(this.keys, i, newKeys, i + 1, this.size - i);

            System.arraycopy(this.pointers, 0, newPointers, 0, i + 1);
            newPointers[i + 1] = rightChild;
            System.arraycopy(this.pointers, i + 1, newPointers, i + 2, this.size - i);

            this.size++;
            if(this.size <= MAX_CHILDREN_FOR_INTERNAL) {
                System.arraycopy(newKeys, 0, this.keys, 0, this.size);
                System.arraycopy(newPointers, 0, this.pointers, 0, this.size + 1);
                return null;
            }

            int m = (this.size / 2);

            // split the internal node
            InternalNode<T, V> newNode = new InternalNode<T, V>();

            newNode.size = this.size - m - 1;
            System.arraycopy(newKeys, m + 1, newNode.keys, 0, this.size - m - 1);
            System.arraycopy(newPointers, m + 1, newNode.pointers, 0, this.size - m);

            // reset the children's parent to the new node.
            for(int j = 0; j <= newNode.size; j++) {
                newNode.pointers[j].parent = newNode;
            }

            this.size = m;
            this.keys = new Object[MAX_CHILDREN_FOR_INTERNAL];
            this.pointers = new Node[MAX_CHILDREN_FOR_INTERNAL];
            System.arraycopy(newKeys, 0, this.keys, 0, m);
            System.arraycopy(newPointers, 0, this.pointers, 0, m + 1);

            if (this.parent == null) {
                this.parent = new InternalNode<T, V>();
            }
            newNode.parent = this.parent;

            return ((InternalNode<T, V>)this.parent).insert((T)newKeys[m], this, newNode);
        }
    }

    /**
     * leaf node, store the keys and actual values.
     * 
     * @author bo.fangbo
     *
     * @param <T>
     * @param <V>
     */
    class LeafNode<T extends Comparable<T>, V> extends Node<T, V> {
        private Object[] values;

        public LeafNode() {
            this.size = 0;
            this.keys = new Object[MAX_FOR_LEAF];
            this.values = new Object[MAX_FOR_LEAF];
            this.parent = null;
        }

        public Node<T, V> insert(T key, V value) {
            Object[] newKeys = new Object[MAX_FOR_LEAF + 1];
            Object[] newValues = new Object[MAX_FOR_LEAF + 1];

            int i = 0;
            for (; i < this.size; i++) {
                T curKey = (T) this.keys[i];

                if (curKey.compareTo(key) == 0) {
                    this.values[i] = value;
                    return null;
                }

                if (curKey.compareTo(key) > 0) break;
            }

            System.arraycopy(this.keys, 0, newKeys, 0, i);
            newKeys[i] = key;
            System.arraycopy(this.keys, i, newKeys, i + 1, this.size - i);

            System.arraycopy(this.values, 0, newValues, 0, i);
            newValues[i] = value;
            System.arraycopy(this.values, i, newValues, i + 1, this.size - i);

            this.size++;

            if (this.size <= MAX_FOR_LEAF){
                System.arraycopy(newKeys, 0, this.keys, 0, this.size);
                System.arraycopy(newValues, 0, this.values, 0, this.size);
                return null;
            }

            // need split this node
            int m = this.size / 2;

            this.keys = new Object[MAX_FOR_LEAF];
            this.values = new Object[MAX_FOR_LEAF];
            System.arraycopy(newKeys, 0, this.keys, 0, m);
            System.arraycopy(newValues, 0, this.values, 0, m);

            LeafNode<T, V> newNode = new LeafNode<T, V>();
            newNode.size = this.size - m;
            System.arraycopy(newKeys, m, newNode.keys, 0, newNode.size);
            System.arraycopy(newValues, m, newNode.values, 0, newNode.size);

            this.size = m;

            if (this.parent == null) {
                this.parent = new InternalNode<T, V>();
            }
            newNode.parent = this.parent;

            return ((InternalNode<T, V>)this.parent).insert((T)newNode.keys[0], this, newNode);
        }

        public V get(T key) {
            // two branch search
            if (this.size == 0) return null;

            int start = 0;
            int end = this.size;

            int middle = (start + end) / 2;

            while (start < end) {
                T middleKey = (T)this.keys[middle];
                if (key.compareTo(middleKey) == 0){
                    break;
                }

                if (key.compareTo(middleKey) < 0) {
                    end = middle;
                } else {
                    start = middle;
                }

                middle = (start + end) / 2;
            }

            T middleKey = (T) this.keys[middle];

            return middleKey.compareTo(key) == 0 ? (V) this.values[middle] : null;
        }
    }


    public static void main(String[] args) {
        BPlusTree<Integer, String> myTree = new BPlusTree<Integer, String>(8);

        int max = 1000000;
        long start = System.currentTimeMillis();
        for(int i = 0; i < max; i++) {
            myTree.set(i, String.valueOf(i));
        }
        System.out.println("time cost with BPlusTree: " + (System.currentTimeMillis() - start));
        System.out.println("Data has been inserted into tree");

        System.out.println("height: " + myTree.height());

        start = System.currentTimeMillis();
        Map<Integer, String> hashMap = new HashMap<Integer, String>();
        for (int i = 0; i < max; i++) {
            hashMap.put(i, String.valueOf(i));
        }
        System.out.println("time cost with HashMap: " + (System.currentTimeMillis() - start));

        for (int i = 0; i < max; i++) {
            if (!String.valueOf(i).equals(myTree.get(i))) {
                System.err.println("error for: " + i);
            }
        }

        System.out.println("Success");
    }
}
展开阅读全文

没有更多推荐了,返回首页