B树

书上和各种资料对B树的定义有很多

下面是一种B树节点的定义和插入实现(java)

import java.util.LinkedList;

public class BTreeNode {
    /**
     * B-树阶数
     */
    int m;
    /**
     * 节点关键字列表
     */
    LinkedList<Integer> values;
    /**
     * 节点父节点
     */
    BTreeNode parent;
    /**
     * 节点的孩子节点列表
     */
    LinkedList<BTreeNode> children;

    public BTreeNode() {
        values = new LinkedList<>();
        children = new LinkedList<>();
    }

    public BTreeNode(int m) {
        this();
        if (m < 3) {
            throw new RuntimeException("The order of B-Tree should be greater than 2.");
        }
        this.m = m;
    }

    /**
     * 根据父亲节点构造孩子节点
     *
     * @param parent
     */
    public BTreeNode(BTreeNode parent) {
        this(parent.m);
        this.parent = parent;
    }

    public BTreeNode insert(int e) {
        if (isEmpty()) {
            values.add(e);
            children.add(new BTreeNode(this));
            children.add(new BTreeNode(this));
            return this;
        }
        BTreeNode p = getRoot().search(e);
        if (!p.isEmpty()) {
            throw new RuntimeException("cannot insert duplicate key to B-Tree, key: " + e);
        }

        return p;
    }

    /**
     * 向指定节点内插入关键字和关键字右侧的孩子节点
     *
     * @param node
     * @param e
     * @param eNode 待插入节点的右侧孩子节点
     */
    private void insertNode(BTreeNode node, int e, BTreeNode eNode) {
        int valueIndex = 0;
        //寻找节点插入的位置
        while (valueIndex < node.values.size() && e < node.values.get(valueIndex)) {
            valueIndex++;
        }
        //插入节点
        node.values.add(valueIndex, e);
        eNode.parent = node;
        //插入孩子节点
        node.children.add(valueIndex + 1, eNode);
        //判断是否需要分裂节点
        if (node.values.size() > m - 1) {
            //分裂位置
            int upIndex = m / 2;
            int up = node.values.get(upIndex);
            // 当前节点分为左右两部分,左部的父节点不变,右部的父节点放在上升关键字右侧
            BTreeNode rNode = new BTreeNode(m);
            rNode.values = new LinkedList<>(node.values.subList(upIndex + 1, m));
            rNode.children = new LinkedList<>(node.children.subList(upIndex, m + 1));
            //因为当前rNode.children的父节点是node 所以将它们指向rNode
            for (BTreeNode child : rNode.children) {
                child.parent = rNode;
            }
            node.values = new LinkedList<>(node.values.subList(0, upIndex));
            node.children = new LinkedList<>(node.children.subList(0, upIndex + 1));
            /**
             * 显然 这是个递归函数 递归结束的条件有两个 第一个是不满足上面的if判断条件 自然不会进入递归函数中
             * 第二个就是当前node节点已经是根节点 显然意味着是根节点关键字数量超出。
             * 此时需要产生一个新的根节点 如下面代码所示 
             */
            if (node.parent == null) {
                node.parent = new BTreeNode(m);
                node.parent.values.add(up);
                node.parent.children.add(node);
                node.parent.children.add(rNode);
                return;
            }
            insertNode(node.parent, up, rNode);
        }
    }

    /**
     * 判断节点是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        if (values == null || values.size() == 0) {
            return true;
        }
        return false;
    }

    /**
     * 获取根节点
     *
     * @return
     */
    public BTreeNode getRoot() {
        BTreeNode p = this;
        while (!p.isRoot()) {
            p = p.parent;
        }
        return p;
    }

    /**
     * 判断是不是根节点
     *
     * @return
     */
    public boolean isRoot() {
        return parent == null;
    }

    /**
     * 从当前节点往下查找目标值target
     *
     * @param target
     * @return 找到则返回找到的节点,不存在则返回叶子节点
     */
    public BTreeNode search(int target) {
        if (isEmpty()) {
            return this;
        }
        int valueIndex = 0;
        while (valueIndex < values.size() && values.get(valueIndex) <= target) {
            if (values.get(valueIndex) == target) {
                return this;
            }
            valueIndex++;
        }
        /**
         * children.get(valueIndex)表示当前节点的最后一个孩子节点
         * 因为当前节点都找完之后 那么值只有可能出现在当前节点的最后的孩子节点(按照节点大小关系)
         */
        return children.get(valueIndex).search(target);
    }

}
import java.util.LinkedList;

public class BTreeNode {
    /**
     * B-树阶数
     */
    int m;
    /**
     * 节点关键字列表
     */
    LinkedList<Integer> values;
    /**
     * 节点父节点
     */
    BTreeNode parent;
    /**
     * 节点的孩子节点列表
     */
    LinkedList<BTreeNode> children;

    public BTreeNode() {
        values = new LinkedList<>();
        children = new LinkedList<>();
    }

    public BTreeNode(int m) {
        this();
        if (m < 3) {
            throw new RuntimeException("The order of B-Tree should be greater than 2.");
        }
        this.m = m;
    }

    /**
     * 根据父亲节点构造孩子节点
     *
     * @param parent
     */
    public BTreeNode(BTreeNode parent) {
        this(parent.m);
        this.parent = parent;
    }

    public BTreeNode insert(int e) {
        if (isEmpty()) {
            values.add(e);
            children.add(new BTreeNode(this));
            children.add(new BTreeNode(this));
            return this;
        }
        BTreeNode p = getRoot().search(e);
        if (!p.isEmpty()) {
            throw new RuntimeException("cannot insert duplicate key to B-Tree, key: " + e);
        }

        return p;
    }

    /**
     * 向指定节点内插入关键字和关键字右侧的孩子节点
     *
     * @param node
     * @param e
     * @param eNode 待插入节点的右侧孩子节点
     */
    private void insertNode(BTreeNode node, int e, BTreeNode eNode) {
        int valueIndex = 0;
        //寻找节点插入的位置
        while (valueIndex < node.values.size() && e < node.values.get(valueIndex)) {
            valueIndex++;
        }
        //插入节点
        node.values.add(valueIndex, e);
        eNode.parent = node;
        //插入孩子节点
        node.children.add(valueIndex + 1, eNode);
        //判断是否需要分裂节点
        if (node.values.size() > m - 1) {
            //分裂位置
            int upIndex = m / 2;
            int up = node.values.get(upIndex);
            // 当前节点分为左右两部分,左部的父节点不变,右部的父节点放在上升关键字右侧
            BTreeNode rNode = new BTreeNode(m);
            rNode.values = new LinkedList<>(node.values.subList(upIndex + 1, m));
            rNode.children = new LinkedList<>(node.children.subList(upIndex, m + 1));
            //因为当前rNode.children的父节点是node 所以将它们指向rNode
            for (BTreeNode child : rNode.children) {
                child.parent = rNode;
            }
            node.values = new LinkedList<>(node.values.subList(0, upIndex));
            node.children = new LinkedList<>(node.children.subList(0, upIndex + 1));
            /**
             * 显然 这是个递归函数 递归结束的条件有两个 第一个是不满足上面的if判断条件 自然不会进入递归函数中
             * 第二个就是当前node节点已经是根节点 显然意味着是根节点关键字数量超出。
             * 此时需要产生一个新的根节点 如下面代码所示 
             */
            if (node.parent == null) {
                node.parent = new BTreeNode(m);
                node.parent.values.add(up);
                node.parent.children.add(node);
                node.parent.children.add(rNode);
                return;
            }
            insertNode(node.parent, up, rNode);
        }
    }

    /**
     * 判断节点是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        if (values == null || values.size() == 0) {
            return true;
        }
        return false;
    }

    /**
     * 获取根节点
     *
     * @return
     */
    public BTreeNode getRoot() {
        BTreeNode p = this;
        while (!p.isRoot()) {
            p = p.parent;
        }
        return p;
    }

    /**
     * 判断是不是根节点
     *
     * @return
     */
    public boolean isRoot() {
        return parent == null;
    }

    /**
     * 从当前节点往下查找目标值target
     *
     * @param target
     * @return 找到则返回找到的节点,不存在则返回叶子节点
     */
    public BTreeNode search(int target) {
        if (isEmpty()) {
            return this;
        }
        int valueIndex = 0;
        while (valueIndex < values.size() && values.get(valueIndex) <= target) {
            if (values.get(valueIndex) == target) {
                return this;
            }
            valueIndex++;
        }
        /**
         * children.get(valueIndex)表示当前节点的最后一个孩子节点
         * 因为当前节点都找完之后 那么值只有可能出现在当前节点的最后的孩子节点(按照节点大小关系)
         */
        return children.get(valueIndex).search(target);
    }

}

 

 

posted @ 2019-12-05 15:32  小小小小的我  阅读(244)  评论(0编辑  收藏  举报