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");
    }
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对您的需求,我可以给您提供一些Java实现B+树的思路和代码示例。希望对您有所帮助! 1. Java实现B+树数据结构 B+树Java实现需要定义节点类和B+树类。节点类包括节点类型(内部节点或叶子节点)、键数组、子节点指针数组、父节点指针、下一个叶子节点指针等属性。B+树类包括根节点指针、阶数、叶子节点链表头指针等属性,以及插入、查找、删除等操作方法。 以下是B+树节点类的Java代码示例: ``` public class BPlusNode<K extends Comparable<K>, V> { // 节点类型:0-内部节点,1-叶子节点 private int type; // 键数组 private K[] keys; // 子节点指针数组 private BPlusNode<K, V>[] children; // 父节点指针 private BPlusNode<K, V> parent; // 下一个叶子节点指针 private BPlusNode<K, V> next; // 数据地址数组,只有叶子节点才有 private List<V> values; // 构造函数 public BPlusNode(int type, int order) { this.type = type; this.keys = (K[]) new Comparable[order + 1]; this.children = (BPlusNode<K, V>[]) new BPlusNode[order + 2]; this.values = new ArrayList<V>(); } // 插入键值对 public void insert(K key, V value) { // 找到插入位置 int pos = 0; while (pos < values.size() && key.compareTo(keys[pos]) > 0) { pos++; } // 插入数据地址 values.add(pos, value); // 插入键 System.arraycopy(keys, pos, keys, pos + 1, values.size() - pos - 1); keys[pos] = key; } // 删除键值对 public void delete(K key) { // 找到删除位置 int pos = 0; while (pos < values.size() && key.compareTo(keys[pos]) > 0) { pos++; } // 删除数据地址 values.remove(pos); // 删除键 System.arraycopy(keys, pos + 1, keys, pos, values.size() - pos); keys[values.size()] = null; } } ``` 以下是B+树类的Java代码示例: ``` public class BPlusTree<K extends Comparable<K>, V> { // 根节点指针 private BPlusNode<K, V> root; // 阶数 private int order; // 叶子节点链表头指针 private BPlusNode<K, V> head; // 构造函数 public BPlusTree(int order) { this.root = new BPlusNode<K, V>(1, order); this.order = order; this.head = root; } // 插入键值对 public void insert(K key, V value) { // 找到插入位置 BPlusNode<K, V> node = findLeafNode(key); // 插入数据地址 node.insert(key, value); // 判断节点是否需要分裂 if (node.values.size() > order) { splitNode(node); } } // 查找键值对 public V search(K key) { // 找到叶子节点 BPlusNode<K, V> node = findLeafNode(key); // 查找数据地址 int pos = 0; while (pos < node.values.size() && key.compareTo(node.keys[pos]) > 0) { pos++; } if (pos < node.values.size() && key.compareTo(node.keys[pos]) == 0) { return node.values.get(pos); } else { return null; } } // 删除键值对 public void delete(K key) { // 找到叶子节点 BPlusNode<K, V> node = findLeafNode(key); // 删除数据地址 node.delete(key); // 判断节点是否需要合并 if (node.parent != null && node.values.size() < (order + 1) / 2) { mergeNode(node); } // 判断根节点是否需要缩小 if (root.children[0] == null) { root = node; } } // 找到叶子节点 private BPlusNode<K, V> findLeafNode(K key) { BPlusNode<K, V> node = root; while (node.type == 0) { int pos = 0; while (pos < node.keys.length && key.compareTo(node.keys[pos]) >= 0) { pos++; } node = node.children[pos]; } return node; } // 分裂节点 private void splitNode(BPlusNode<K, V> node) { // 分裂后,左节点包含的数据地址数目为(order+1)/2,右节点包含的数据地址数目为order+1-(order+1)/2 int mid = (order + 1) / 2; BPlusNode<K, V> left = new BPlusNode<K, V>(node.type, order); BPlusNode<K, V> right = new BPlusNode<K, V>(node.type, order); if (node.parent == null) { // 分裂根节点 BPlusNode<K, V> parent = new BPlusNode<K, V>(0, order); parent.children[0] = left; parent.children[1] = right; parent.keys[0] = node.keys[mid - 1]; left.parent = parent; right.parent = parent; root = parent; } else { // 分裂内部节点或叶子节点 BPlusNode<K, V> parent = node.parent; int pos = 0; while (pos < parent.children.length && parent.children[pos] != node) { pos++; } parent.insert(node.keys[mid - 1], null); System.arraycopy(node.children, 0, left.children, 0, mid); System.arraycopy(node.children, mid, right.children, 0, order + 1 - mid); System.arraycopy(node.keys, 0, left.keys, 0, mid - 1); System.arraycopy(node.keys, mid, right.keys, 0, order - mid); left.parent = parent; right.parent = parent; parent.children[pos] = left; parent.children[pos + 1] = right; if (parent.values.size() > order) { splitNode(parent); } } if (node.type == 1) { // 更新叶子节点链表 left.next = right; right.next = node.next; node.next = null; if (node == head) { head = left; } } } // 合并节点 private void mergeNode(BPlusNode<K, V> node) { // 合并后,父节点中的键和子节点指针数目减1 BPlusNode<K, V> parent = node.parent; int pos = 0; while (pos < parent.children.length && parent.children[pos] != node) { pos++; } if (pos == 0) { // 合并左节点和右节点 BPlusNode<K, V> right = parent.children[pos + 1]; node.keys[node.values.size()] = parent.keys[0]; System.arraycopy(right.children, 0, node.children, node.values.size(), right.values.size()); System.arraycopy(right.keys, 0, node.keys, node.values.size() + 1, right.values.size()); node.values.addAll(right.values); node.next = right.next; if (right.next != null) { right.next.parent = node; } parent.delete(parent.keys[0]); parent.children[pos + 1] = null; } else { // 合并左节点和右节点 BPlusNode<K, V> left = parent.children[pos - 1]; left.keys[left.values.size()] = parent.keys[pos - 1]; System.arraycopy(node.children, 0, left.children, left.values.size(), node.values.size()); System.arraycopy(node.keys, 0, left.keys, left.values.size() + 1, node.values.size()); left.values.addAll(node.values); left.next = node.next; if (node.next != null) { node.next.parent = left; } parent.delete(parent.keys[pos - 1]); parent.children[pos] = null; } if (parent.parent != null && parent.values.size() < (order + 1) / 2) { mergeNode(parent); } } } ``` 2. 构造100条数据,并加入B+树 构造100条数据很简单,您可以随机生成100个整数作为键,然后将它们与一些数据地址关联起来。接下来,您需要将这些数据插入到B+树中。插入操作需要从根节点开始遍历,找到合适的叶子节点,然后将键和数据地址插入到叶子节点中。如果插入后导致节点超过了容量限制,就需要进行分裂操作。具体实现可以参考B+树的算法。 以下是Java代码示例: ``` // 构造100条数据 Map<Integer, String> map = new HashMap<>(); Random random = new Random(); for (int i = 0; i < 100; i++) { int key = random.nextInt(1000); String value = "data-" + i; map.put(key, value); } // 加入B+树 BPlusTree<Integer, String> tree = new BPlusTree<>(4); for (Map.Entry<Integer, String> entry : map.entrySet()) { int key = entry.getKey(); String value = entry.getValue(); tree.insert(key, value); } ``` 3. 构造测试用例 构造测试用例的目的是验证B+树的正确性和性能。您可以设计一些测试用例,例如: - 测试B+树的插入和查找操作,验证数据是否能够正确地插入和查找。 - 测试B+树的删除操作,验证数据是否能够正确地删除,并且删除后B+树是否能够保持平衡。 - 测试B+树的性能,包括插入、查找、删除操作的时间和空间复杂度,以及B+树的存储效率和查询效率。 以下是Java代码示例: ``` // 测试插入和查找操作 for (Map.Entry<Integer, String> entry : map.entrySet()) { int key = entry.getKey(); String value = entry.getValue(); String result = tree.search(key); assert result.equals(value); } // 测试删除操作 for (Map.Entry<Integer, String> entry : map.entrySet()) { int key = entry.getKey(); tree.delete(key); String result = tree.search(key); assert result == null; } // 测试性能 long startTime = System.currentTimeMillis(); for (Map.Entry<Integer, String> entry : map.entrySet()) { int key = entry.getKey(); String value = entry.getValue(); tree.insert(key, value); } long endTime = System.currentTimeMillis(); System.out.println("插入100条数据用时:" + (endTime - startTime) + "ms"); startTime = System.currentTimeMillis(); for (Map.Entry<Integer, String> entry : map.entrySet()) { int key = entry.getKey(); String result = tree.search(key); } endTime = System.currentTimeMillis(); System.out.println("查找100条数据用时:" + (endTime - startTime) + "ms"); startTime = System.currentTimeMillis(); for (Map.Entry<Integer, String> entry : map.entrySet()) { int key = entry.getKey(); tree.delete(key); } endTime = System.currentTimeMillis(); System.out.println("删除100条数据用时:" + (endTime - startTime) + "ms"); ``` 以上是B+树Java实现思路和代码示例,希望对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值