B-树的java实现

理论部分见:B-树的理论学习

JAVA实现

定义树结点类

/**
     * B-树的结点类
     */
    private static class Node {

        /**
         * 关键字列表
         */
        private final List<Object> keyList;
        /**
         * 孩子结点列表
         */
        private final List<Node> childNodesList;
        /**
         * 是否叶子结点
         */
        private boolean isLeaf;
        /**
         * 双亲结点
         */
        private Node parentNode;

        /**
         * 键值比较函数对象,如果采用倒序或者其它排序方式,传入该对象
         */
        private Comparator<Object> kComparator;

        public Node() {
            this.keyList = new LinkedList<>();
            this.childNodesList = new LinkedList<>();
            this.isLeaf = false;
        }

        /**
         * 自定义K排序方式的构造函数
         */
        public Node(Comparator<Object> kComparator) {
            this();
            this.kComparator = kComparator;
        }

        /**
         * 比较两个key,如果没有传入自定义排序方式则采用默认的升序
         */
        private int compare(Object key1, Object key2) {
            return this.kComparator == null ? ((Comparable<Object>) key2).compareTo(key1) : kComparator.compare(key1, key2);
        }


        public void setIsLeaf(boolean isLeaf) {
            this.isLeaf = isLeaf;
        }

        public boolean getIsLeaf() {
            return this.isLeaf;
        }

        public void setParentNode(Node parentNode) {
            this.parentNode = parentNode;
        }

        public Node getParentNode() {
            return parentNode;
        }

        /**
         * 结点中关键字的个数
         */
        public int keySize() {
            return this.keyList.size();
        }

        /**
         * 采用二分查找在结点内查找关键字
         */
        public SearchResult searchResult(Object key) {
            int begin = 0;
            int end = this.keySize() - 1;
            int mid = (begin + end) / 2;
            boolean isExist = false;
            int index = 0;
            //二分查找
            while (begin < end) {
                mid = (begin + end) / 2;
                Object midValue = this.keyList.get(mid);
                int compareRe = compare(midValue, key);
                //找到了
                if (compareRe == 0) {
                    break;
                } else {
                    if (compareRe > 0) {
                        //在中点右边
                        begin = mid + 1;
                    } else {
                        end = mid - 1;
                    }
                }
            }
            //二分查找结束,判断结果;三个元素以上才是正经二分,只有两个或一个元素属于边界条件要着重考虑
            if (begin < end) {
                //找到了
                isExist = true;
                index = mid;
            } else if (begin == end) {
                Object midKey = this.keyList.get(begin);
                int comRe = compare(midKey, key);
                if (comRe == 0) {
                    isExist = true;
                    index = begin;
                } else if (comRe > 0) {
                    index = begin + 1;
                } else {
                    index = begin;
                }
            } else {
                index = begin;
            }
            return new SearchResult(isExist, index, null);
        }

    }

定义查询key的结果类

/**
     * 关键字查询结果类
     */
    private static class SearchResult {
        /**
         * 关键字所在结点
         */
        private final Node node;
        /**
         * 是否存在
         */
        private final boolean isExist;
        /**
         * 下标
         */
        private final int index;

        public SearchResult(boolean isExist, int index, Node node) {
            this.isExist = isExist;
            this.index = index;
            this.node = node;
        }

        public boolean isExist() {
            return isExist;
        }

        public int getIndex() {
            return index;
        }

        public Node getNode() {
            return node;
        }
    }

定义树类

public class MyBTree {

...
...
...

    /**
     * 默认3阶树
     */
    private final Integer DEFAULT_ORDER = 3;

    /**
     * 树阶
     */
    private int order = DEFAULT_ORDER;

    /**
     * 结点中关键字个数的最大值
     */
    private int maxKeySize = order - 1;

    /**
     * 结点的最小关键字数
     */
    private int nonLeafMinKeys = (int) Math.ceil(order / 2.0) - 1;

    /**
     * 根结点
     */
    private Node root;

    /**
     * 比较函数对象
     */
    private Comparator<Object> kComparator;

    /**
     * 构造一棵自然排序的B树
     */
    MyBTree() {
        Node root = new Node();
        this.root = root;
        root.setIsLeaf(true);
    }

    /**
     * 构造一棵order阶 的B树
     */
    MyBTree(int order) {
        this();
        this.order = order;
        this.maxKeySize = order - 1;
        this.nonLeafMinKeys = (int) Math.ceil(order / 2.0) - 1;
    }

...
...
...

}

类图

java 树导出 java怎么实现树_java 树导出

NodeSearchResultBtree的子类,由入口main方法执行验证。若有BUG,可以留言。

完整

package tree.b;

import java.util.*;

public class MyBTree<K> {

    /**
     * 关键字查询结果类
     */
    private static class SearchResult {
        /**
         * 关键字所在结点
         */
        private final Node node;
        /**
         * 是否存在
         */
        private final boolean isExist;
        /**
         * 下标
         */
        private final int index;

        public SearchResult(boolean isExist, int index, Node node) {
            this.isExist = isExist;
            this.index = index;
            this.node = node;
        }

        public boolean isExist() {
            return isExist;
        }

        public int getIndex() {
            return index;
        }

        public Node getNode() {
            return node;
        }
    }

    /**
     * B-树的结点类
     */
    private static class Node {

        /**
         * 关键字列表
         */
        private final List<Object> keyList;
        /**
         * 孩子结点列表
         */
        private final List<Node> childNodesList;
        /**
         * 是否叶子结点
         */
        private boolean isLeaf;
        /**
         * 双亲结点
         */
        private Node parentNode;

        /**
         * 键值比较函数对象,如果采用倒序或者其它排序方式,传入该对象
         */
        private Comparator<Object> kComparator;

        public Node() {
            this.keyList = new LinkedList<>();
            this.childNodesList = new LinkedList<>();
            this.isLeaf = false;
        }

        /**
         * 自定义K排序方式的构造函数
         */
        public Node(Comparator<Object> kComparator) {
            this();
            this.kComparator = kComparator;
        }

        /**
         * 比较两个key,如果没有传入自定义排序方式则采用默认的升序
         */
        private int compare(Object key1, Object key2) {
            return this.kComparator == null ? ((Comparable<Object>) key2).compareTo(key1) : kComparator.compare(key1, key2);
        }


        public void setIsLeaf(boolean isLeaf) {
            this.isLeaf = isLeaf;
        }

        public boolean getIsLeaf() {
            return this.isLeaf;
        }

        public void setParentNode(Node parentNode) {
            this.parentNode = parentNode;
        }

        public Node getParentNode() {
            return parentNode;
        }

        /**
         * 结点中关键字的个数
         */
        public int keySize() {
            return this.keyList.size();
        }

        /**
         * 采用二分查找在结点内查找关键字
         */
        public SearchResult searchResult(Object key) {
            int begin = 0;
            int end = this.keySize() - 1;
            int mid = (begin + end) / 2;
            boolean isExist = false;
            int index = 0;
            //二分查找
            while (begin < end) {
                mid = (begin + end) / 2;
                Object midValue = this.keyList.get(mid);
                int compareRe = compare(midValue, key);
                //找到了
                if (compareRe == 0) {
                    break;
                } else {
                    if (compareRe > 0) {
                        //在中点右边
                        begin = mid + 1;
                    } else {
                        end = mid - 1;
                    }
                }
            }
            //二分查找结束,判断结果;三个元素以上才是正经二分,只有两个或一个元素属于边界条件要着重考虑
            if (begin < end) {
                //找到了
                isExist = true;
                index = mid;
            } else if (begin == end) {
                Object midKey = this.keyList.get(begin);
                int comRe = compare(midKey, key);
                if (comRe == 0) {
                    isExist = true;
                    index = begin;
                } else if (comRe > 0) {
                    index = begin + 1;
                } else {
                    index = begin;
                }
            } else {
                index = begin;
            }
            return new SearchResult(isExist, index, null);
        }

    }

    /**
     * 默认3阶树
     */
    private final Integer DEFAULT_ORDER = 3;

    /**
     * 树阶
     */
    private int order = DEFAULT_ORDER;

    /**
     * 结点中关键字个数的最大值
     */
    private int maxKeySize = order - 1;

    /**
     * 结点的最小关键字数
     */
    private int nonLeafMinKeys = (int) Math.ceil(order / 2.0) - 1;

    /**
     * 根结点
     */
    private Node root;

    /**
     * 比较函数对象
     */
    private Comparator<Object> kComparator;

    /**
     * 构造一棵自然排序的B树
     */
    MyBTree() {
        Node root = new Node();
        this.root = root;
        root.setIsLeaf(true);
    }

    /**
     * 构造一棵order阶 的B树
     */
    MyBTree(int order) {
        this();
        this.order = order;
        this.maxKeySize = order - 1;
        this.nonLeafMinKeys = (int) Math.ceil(order / 2.0) - 1;
    }

    /**
     * 在以node为根的树内搜索key项
     */
    private SearchResult search(Node node, Object key) {
        SearchResult re = node.searchResult(key);
        if (re.isExist()) {
            return new SearchResult(true, re.getIndex(), node);
        } else {
            // 叶子结点
            if (node.getIsLeaf()) {
                return new SearchResult(false, re.getIndex(), node);
            }
            int index = re.getIndex();
            //递归搜索子结点--index是在查询结点内关键字的下标 也是子结点的下标
            return search(node.childNodesList.get(index), key);
        }
    }

    public boolean insertKey(Object key) {
        // 查询key在树中的结点情况
        SearchResult searchResult = search(root, key);
        if (searchResult.isExist()) {
            //已存在key,直接返回
            return false;
        }

        // 找出根结点
        if (null == searchResult.getNode().parentNode) {
            return insertKey(root, searchResult.getIndex(), key);
        } else {
            return insertKey(searchResult.getNode(), searchResult.getIndex(), key);
        }
    }

    private boolean insertKey(Node node, int index, Object key) {
        node.keyList.add(index, key);
        if (node.keyList.size() > maxKeySize) {
            // 分裂
            splitNode(node);
        }
        return true;
    }

    /**
     * 分裂结点
     */
    private void splitNode(Node node) {
        //取结点中间key下标
        int midIndex = node.keyList.size() / 2;
        Object key = node.keyList.get(midIndex);

        Node newNode = new Node();
        // 新结点采用原来结点是否是叶子结点的值
        newNode.setIsLeaf(node.getIsLeaf());
        // 新结点取源结点的(midIndex,node.keyList.size()-1]的关键字
        for (int i = midIndex + 1; i < node.keyList.size(); i++) {
            newNode.keyList.add(node.keyList.get(i));
        }
        // 源结点只留下标为[0,midIndex)的关键字
        if (node.keyList.size() > midIndex) {
            node.keyList.subList(midIndex, node.keyList.size()).clear();
        }

        // 若叶子结点,需要将原来结点的孩子结点也进行分裂,新结点取(midIndex,node.keyList.size()-1]的孩子结点
        if (!node.isLeaf) {
            for (int i = midIndex + 1; i < node.childNodesList.size(); i++) {
                newNode.childNodesList.add(node.childNodesList.get(i));
                // 修改孩子结点的双亲结点为新结点
                node.childNodesList.get(i).setParentNode(newNode);
            }
            // 源结点只留下标为[0,midIndex]的孩子结点
            if (node.childNodesList.size() > midIndex + 1) {
                node.childNodesList.subList(midIndex + 1, node.childNodesList.size()).clear();
            }
        }


        Node father = node.getParentNode();

        if (null == father) {
            // 若结点的双亲结点为null,说明是根结点进行的分裂,需要新增结点作为根结点
            father = new Node();
            father.childNodesList.add(node);
            father.setIsLeaf(false);
            father.keyList.add(key);
            father.childNodesList.add(newNode);
            node.parentNode = father;
            newNode.parentNode = father;
        } else {
            newNode.parentNode = father;
            SearchResult re = father.searchResult(key);
            father.keyList.add(re.getIndex(), key);
            father.childNodesList.add(re.getIndex() + 1, newNode);
            // 若双亲的关键字个数超出最大允许值,则继续分裂
            if (father.keyList.size() > maxKeySize) {
                splitNode(father);
            }
        }

        if (father.getParentNode() == null) {
            this.root = father;
        }
    }

    public boolean deleteKey(Object key) {

        SearchResult searchResult = search(root, key);

        // 没有找到key 直接结束
        if (!searchResult.isExist()) {
            return false;
        }

        Node keyInNode = searchResult.getNode();
        // 是否是叶子结点
        if (!keyInNode.getIsLeaf()) {

            // 非叶子结点,取第i个孩子结点中的最大关键字
            Node keyChildNode = keyInNode.childNodesList.get(searchResult.getIndex());
            //如果孩子结点不是叶子结点,去找这个子树到叶子结点中最大的关键字,与key互换位置
            if (!keyChildNode.getIsLeaf()) {
                keyChildNode = getMaxLeaf(keyChildNode);
            }
            Object childMinkey = keyChildNode.keyList.get(keyChildNode.keyList.size() - 1);
            keyInNode.keyList.add(searchResult.getIndex(), childMinkey);
            keyInNode.keyList.remove(key);
            keyChildNode.keyList.remove(childMinkey);
            keyChildNode.keyList.add(key);
            keyInNode = keyChildNode;
        }

        return deleteKey(keyInNode, key);
    }

    /**
     * 获取node结点到最右侧子结点的叶子结点
     * @param node
     * @return
     */
    private Node getMaxLeaf(Node node) {
        Node keyChildNode = node.childNodesList.get(node.childNodesList.size() - 1);
        if (!keyChildNode.getIsLeaf()) {
            getMaxLeaf(keyChildNode);
        }
        return keyChildNode;
    }

    public boolean deleteKey(Node node, Object key) {
        // 如果需要删除关键字的结点,原本的关键字个数超过Math.ceil(order / 2.0) - 1
        if (node.keyList.size() > nonLeafMinKeys) {
            node.keyList.remove(key);
            return true;
        }

        // 如果需要删除关键字的结点,原本的关键字个数不超过Math.ceil(order / 2.0) - 1
        if (node.keyList.size() == nonLeafMinKeys) {
            doManageNode(node, key);
        }

        return true;
    }

    private void doManageNode(Node node, Object key) {
        if (null == node.parentNode) {
            return;
        }
        // 找兄弟结点中是否存在关键字个数超过Math.ceil(order / 2.0) - 1的
        int nodeIndex = node.parentNode.childNodesList.indexOf(node);
        Node leftNode = null;
        Node rightNode = null;
        if (0 <= nodeIndex && nodeIndex < node.parentNode.childNodesList.size() - 1) {
            rightNode = node.parentNode.childNodesList.get(nodeIndex + 1);
        }
        if (0 < nodeIndex) {
            leftNode = node.parentNode.childNodesList.get(nodeIndex - 1);
        }

        if (null != leftNode && leftNode.keyList.size() > nonLeafMinKeys) {
            node.parentNode.keyList.add(nodeIndex - 1, leftNode.keyList.get(leftNode.keyList.size() - 1));
            node.keyList.add(0, node.parentNode.keyList.get(node.parentNode.keyList.size() - 1));
            node.parentNode.keyList.remove(node.parentNode.keyList.size() - 1);
            node.keyList.remove(key);
            leftNode.keyList.remove(leftNode.keyList.get(leftNode.keyList.size() - 1));
            return;
        }

        if (null != rightNode && rightNode.keyList.size() > nonLeafMinKeys) {
            node.parentNode.keyList.add(nodeIndex + 1, rightNode.keyList.get(0));
            node.keyList.add(node.parentNode.keyList.get(nodeIndex));
            node.parentNode.keyList.remove(nodeIndex);
            node.keyList.remove(key);
            rightNode.keyList.remove(rightNode.keyList.get(0));
            return;
        }

        // 左右兄弟结点的关键字个数都不足的话,合并兄弟结点,下放一个双亲结点的关键字
        if (leftNode != null) {
            //合并结点
            node = merge(leftNode, node);
            node.keyList.remove(key);

            if (node.parentNode.keyList.size() < nonLeafMinKeys && null != node.parentNode.parentNode) {
                // 寻找结点合并
                doManageNode(node.parentNode, null);
            }

            if (null == node.parentNode.parentNode && node.parentNode.keyList.isEmpty()) {
                root = node;
            }
            return;
        }

        if (rightNode != null) {
            //合并结点
            node = merge(node, rightNode);
            node.keyList.remove(key);

            if (node.parentNode.keyList.size() < nonLeafMinKeys && null != node.parentNode.parentNode) {
                // 寻找结点合并
                doManageNode(node.parentNode, null);
            }
            if (null == node.parentNode.parentNode && node.parentNode.keyList.isEmpty()) {
                root = node;
            }
        }
    }

    private Node merge(Node leftNode, Node rightNode) {
        int index = leftNode.parentNode.childNodesList.indexOf(leftNode);
        leftNode.keyList.add(leftNode.parentNode.keyList.get(index));
        leftNode.parentNode.keyList.remove(index);
        leftNode.keyList.addAll(rightNode.keyList);
        if (!rightNode.isLeaf) {
            leftNode.childNodesList.addAll(rightNode.childNodesList);
        }
        leftNode.parentNode.childNodesList.remove(rightNode);
        return leftNode;
    }

    public static void main(String[] args) {
        List<Integer> save = new ArrayList<Integer>(30);
        MyBTree<Integer> btree = new MyBTree<>(3);
        save.add(45);
        save.add(24);
        save.add(90);
        save.add(3);
        save.add(27);
        save.add(70);
        save.add(100);
        save.add(62);
        for (int r : save) {
            System.out.print(r + "  ");
            btree.insertKey(r);
        }
        System.out.println("");
        System.out.println("----------------------");
        btree.output();
        System.out.println("----------------------");
        btree.deleteKey(45);
        btree.output();
    }

    public void output() {
        Queue<Node> queue = new LinkedList<>();
        queue.offer(this.root);
        while (!queue.isEmpty()) {
            Node node = queue.poll();
            for (int i = 0; i < node.keyList.size(); ++i) {
                System.out.print(node.keyList.get(i) + " ");
            }
            System.out.println();
            if (!node.getIsLeaf()) {
                for (int i = 0; i <= node.childNodesList.size() - 1; ++i) {
                    queue.offer(node.childNodesList.get(i));
                }
            }
        }
    }

}