btree 实现

btree的使用场景

在巨型数据集中,查找是一项非常耗时的操作。我们希望设计一种这样的数据结构,通过简单的4-5指向数据块的引用就能查找到巨型数据集中我们想要的数据。这时,btree就诞生了。我们以前学习的高效查找结构,如红黑树等,适用于能够存放到内存中的数据。btree主要用于对磁盘或者网络上的数据的查找。如mysql 的存储引擎myisam就是btree的实现。

b-树的数据结构

  • b树的节点是页。页中存放的数据是一段连续有序的数据。
  • 在b树中,我们不会把数据存放到内存中(数据存放到外部磁盘或者网络上)。而是构造一颗由键的副本组成的树。
  • 页中键的副本时有序的。
  • 对于一颗M阶的树,每个节点最少含有M/2个键和链接,最多含有M-1个键和链接。根节点除外,跟节点可以含有小于M/2的键和链接。
  • 父节点的键值时内部节点的最小值。

    对于B-树的内部约定:
    - 内部节点:含有与页相关联的键的副本。
    - 外部节点:含有指向实际数据的引用。
    

    图解:
    这里写图片描述

B -树 官方定义

一颗M阶B-树(M为正偶数)或者仅是一个外部k-节点(或者k个键和相关信息的树),或者由若干内部k-节点(每个节点都含有k个键和k条连接,链接指向的子树表示了键之间的间隔区域)组成。它的结构性质如下:从跟节点到每个外部节点的路径长度均相同(完美平衡);对于跟节点,k在2到M-1之间,对于其他节点k在M/2到M-1之间。

B - 树 java实现

数据页定义
@Data
    public static class Page {
        /**
         * 存放键值对
         */
        public Entity[] entitys = new Entity[M];

        public int m = 0;

        /*定义页的父节点*/
        public Page pPage;

        public Page() { 
        }

        public Page(int m) {
            this.m = m;
        }

        /**
         * 判断节点是否是满的
         * @return
         */
        public boolean isFull() {
            if (m == M) {
                return true;
            }
            return false;
        }

        /**
         * 键在此页中
         * @param key
         * @return
         */
        public boolean contains(Entity entity) {
            return binarySearch(entitys,entity.keyName) == -1?false:true;
        }

        /**
         * 获取元素的下一个插入点
         * @param entity
         * @return
         */
        public Page next(Entity entity) {
            if (contains(entity)) {
                return entity.page;
            }
            else {
                int len = entitys.length;
                for (int i = len - 1;i >= 0;i--) {
                    if (entitys[i] != null) {
                        if (entity.keyName.compareTo(entitys[i].keyName) > 0) {
                            return entitys[i].page;
                        }
                    }
                }
            }
            return null;
        }

        public void addEntity(Entity entity) {
            entitys[m] = entity;
            for (int i = m - 1;i >= 0; i--) {
                if (entitys[i].keyName.compareTo(entity.keyName) > 0) {
                    Entity tempEntity = entitys[i];
                    entitys[i] = entity;
                    entitys[i+1] = tempEntity;
                } else {
                    break;
                }
            }
            m = m + 1;
        }

        public void add(Page page) {
            if (page.m > 0) {
                String keyName = page.entitys[0].keyName;
                addEntity(new Entity(keyName,null,page));
            }
        }

        /**
         * 分隔页
         * @return
         */
        public Page splitPage() {
            Page page = new Page();
            System.arraycopy(entitys,M/2,page.entitys,0,M-M/2);
            page.m = M- (M/2);
            for (int i = M/2;i < M;i++) {
                entitys[i] = null;
            }
            this.m = M/2;

            return page;
        }

        /**
         * 二分搜索
         * @param entitys
         * @param keyName
         * @return
         */
        public int binarySearch(Entity[] entitys,String keyName) {
            int start = 0;
            int end = entitys.length - 1;
            while(start <= end) {
                int mid = start + (end - start) / 2;
                if (entitys[mid] == null) {
                    break;
                }
                if (keyName.equals(entitys[mid].keyName)) {
                    return mid;
                }
                else if (keyName.compareTo(entitys[mid].keyName) < 0) {
                     end = mid -1;
                } else if (keyName.compareTo(entitys[mid].keyName) > 0) {
                    start = mid + 1;
                }
            }
            return -1;
        }
    }
    @Data
    public static class Entity {
        public String keyName;
        /*外部节点*/
        public String val;
        /*内部节点*/
        public Page page;

        public Entity(String keyName,String val,Page page) {
            this.keyName = keyName;
            this.val = val;
            this.page = page;
        }
    }
构建B-树
@Data
public class Btree {
    //btree树的界
    private static int M = 6;

    //根节点
    private Page root = new Page(0);

    //定义树的高度
    private int height;

    /**
     * 往b树中添加元素
     * @param key
     * @param value
     */
    public void add(String key,String value) {
        Entity entity = new Entity(key,value,null);
        add(root,entity,height);
        /**
         * 如果元素已满,则分列
         */
        if (root.isFull()) {
            Page temp = root;
            Page rightPage = root.splitPage();
            Page leftPage = root;
            rightPage.pPage = temp;
            leftPage.pPage = temp;
            root = new Page(0);
            root.add(leftPage);
            root.add(rightPage);
            height = height + 1;
        }
    }

    private void add(Page page,Entity key,int hi) {
        /*页节点*/
        if (hi == 0) {
            page.addEntity(key);
        } else {
            Page nextPage = page.next(key);
            add(nextPage,key,hi - 1);
            if (nextPage.isFull()) {
                Page splitPage = nextPage.splitPage();
                page.add(splitPage);
            }
        }
    }

    public int height() {
        return height;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值