B-树的java实现

Posted 顧棟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了B-树的java实现相关的知识,希望对你有一定的参考价值。

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;
    

...
...
...


类图

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();以上是关于B-树的java实现的主要内容,如果未能解决你的问题,请参考以下文章

从JVM的角度看JAVA代码--代码优化

片段 A 的列表视图中的片段 B 中的新列表视图,单击 A 的列表项

java基础编程——树的子结构

剑指offer——树的子结构

树的层次遍历(Java代码实现)

Python数据结构系列☀️《查找排序-基础知识》——知识点讲解+代码实现☀️