B树-插入

B树系列文章

1. B树-介绍

2. B树-查找

3. B树-插入

4. B树-删除

插入

根据B树的以下两个特性

  • 每一个结点最多有m个子结点
  • 有k个子结点的非叶子结点拥有 k − 1 个键

可以得出,B树每个结点存放键的数量是有上限的是m-1,因此插入操作可能导致结点”溢出”。

插入操作的重点和难点在于结点”溢出”后的再平衡操作

假设有一棵3阶B树,如下图所示。

通过给这棵3阶B树插入键值53,来分析B树插入键值的过程。

首先,参考查找的步骤,最终定位到53应该插入到Node21结点的最后

但是这是一个3阶B树,每个结点拥有键的最大数量为2,因此插入53会导致Node21″溢出”

B树-插入

由于Node21结点”溢出”,需要对Node21进行拆分,拆分方法如下

  • 从该结点的原有键和新的键中选择出中位数,这个中位数作为分隔值
  • 小于这一中位数的键放入左边结点,大于这一中位数的键放入右边结点,中位数作为分隔值。
  • 分隔值被插入到父结点中,这可能会造成父结点分裂,分裂父结点时可能又会使它的父结点分裂,以此类推。如果没有父结点(这一结点是根结点),就创建一个新的根结点(增加了树的高度)。

下图是对Node21进行拆分的结果,Node21分裂成两个新的结点和分隔值53,53需要插入父结点中

B树-插入

将分隔值插入父结点中,形成Node2结点,原来的Node21结点被拆分为新的Node21和Node22结点

可以看出来,此时Node2结点键的数量达到了阶数,即达到”溢出”条件了

因此,需要继续对Node2进行拆分

B树-插入

对Node2进行拆分,中间值55提升到root结点,原来的Node2结点拆分成Node2和Node3两个新结点

同样的,此时root结点也”溢出”了,需要对root结点进行拆分

对root结点的拆分,最终造成B树高度的增加

B树-插入

对根结点进行拆分,55被提升,需要创建新的根结点存放键55,键值40和70分别构成新的两个儿子结点,分别是Node1和Node12

此时B数重新平衡了。

B树-插入

这里总结下

所有的插入都从根结点开始。要插入一个新的键,首先搜索这棵树找到新键应该被添加到的对应结点。将新键插入到这一结点中的步骤如下:

如果结点拥有的键数量小于最大值,那么有空间容纳新的键。将新键插入到这一结点,且保持结点中键有序。

否则的话这一结点已经满了,将它平均地拆分成两个结点:

从该结点的原有键和新的键中选择出中位数

小于这一中位数的键放入左边结点,大于这一中位数的键放入右边结点,中位数作为分隔值。

分隔值被插入到父结点中,这可能会造成父结点分裂,分裂父结点时可能又会使它的父结点分裂,以此类推。如果没有父结点(这一结点是根结点),就创建一个新的根结点(增加了树的高度)。

这里是插入的代码

/**
* 插入key
* 时间复杂度为O(logn)
**/
func (bTreeNode *BTreeNode) intert(key int, m int) ([]*BTreeNode, int) {
    // 找到第一个不比key小的,注意leaf的数量比key数量多1
    idx := 0
    for idx < bTreeNode.keyNum && key > bTreeNode.keyList[idx] {
        idx++
    }

    // BTreeNode已有该key
    if idx < bTreeNode.keyNum && bTreeNode.keyList[idx] == key {
        return nil, 0
    }

    if bTreeNode.isLeaf { // 叶子结点
        // idx及idx后面元素往后移动
        if idx < m-1 {
            copy(bTreeNode.keyList[idx+1:], bTreeNode.keyList[idx:])
        }
        bTreeNode.keyList[idx] = key
        bTreeNode.keyNum += 1
    } else { // 非叶子结点
        // 判断结点是否要满了
        // 先往上提
        children, midKey := bTreeNode.leafList[idx].intert(key, m)
        if children != nil {
            // idx是midKey的插入位置,idx后面元素往后移动
            if idx < m-1 {
                copy(bTreeNode.keyList[idx+1:], bTreeNode.keyList[idx:])
                copy(bTreeNode.leafList[idx+2:], bTreeNode.leafList[idx+1:])
            }
            bTreeNode.keyList[idx] = midKey
            bTreeNode.leafList[idx] = children[0]
            bTreeNode.leafList[idx+1] = children[1]
            bTreeNode.keyNum += 1
        }
    }

    if bTreeNode.keyNum == m { // 节点key数量超了
        // 从中间将该结点一分为2
        mid := bTreeNode.keyNum / 2
        midKey := bTreeNode.keyList[mid]

        // 左儿子
        leftNode := createNode(m, mid, bTreeNode.isLeaf)
        copy(leftNode.keyList, bTreeNode.keyList[:mid])
        copy(leftNode.leafList, bTreeNode.leafList[:mid+1])

        // 右边儿子
        rightNode := createNode(m, m-mid-1, bTreeNode.isLeaf)
        copy(rightNode.keyList, bTreeNode.keyList[mid+1:])
        copy(rightNode.leafList, bTreeNode.leafList[mid+1:])

        return []*BTreeNode{leftNode, rightNode}, midKey
    }
    return nil, 0
}

/** 插入key
* 时间复杂度O(logn)
**/
func (bTree *BTree) Insert(key int) {
    children, midKey := bTree.root.intert(key, bTree.m)
    if children != nil {
        root := createNode(bTree.m, 1, false)
        root.keyList[0] = midKey
        root.leafList[0] = children[0]
        root.leafList[1] = children[1]
        bTree.root = root
    }
}

Original: https://www.cnblogs.com/amos01/p/16492334.html
Author: Amos01
Title: B树-插入

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/642747/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 关于方法的几点思考

    1.概念陈述 成法,即为已经存在的方法,他是经过时间的洗礼、先哲们千锤百炼而流传下来的具有解决已知问题成效的方法. 改法,即为在已经存在的方法之上加以修改,使之成为具备解决普遍问题…

    技术杂谈 2023年5月31日
    079
  • 为什么HDFS的block不能设置太大或太小

    寻址时间为传输时间的1%时,则为最佳状态。 一个大文件会被分为多个block存在hdfs中,而每个block对于磁盘来说就是一个文件。 该hdfs的大文件寻址时间是等于磁盘寻找每个…

    技术杂谈 2023年7月23日
    071
  • BlazorVSVue

    Vue——​​两分钟概述 Vue 是一个JavaScript 框架。 在其最简单的模式中,您可以简单地将核心 Vue 脚本包含在您的应用程序中,然后开始构建您的组件。 除此之外,对…

    技术杂谈 2023年7月24日
    069
  • SkyWalking

    目前主要的一些 APM (Application Performance Management) 工具有: Cat、Zipkin、Pinpoint、SkyWalking, 监控维度…

    技术杂谈 2023年5月31日
    075
  • excel表格宏的启用

    这两张图片都可以启用宏,任何一种方式都可以 方式1 方式2 posted @2022-03-26 16:27 LiuYanYGZ 阅读(383 ) 评论() 编辑 Original…

    技术杂谈 2023年5月31日
    077
  • Vue 项目中遇到的跨域问题及解决方法

    问题描述 前端 vue 框架,跨域问题后台加这段代码header(“Access-Control-Allow-Origin: *”);加了之后报这个错: T…

    技术杂谈 2023年6月1日
    098
  • 超详细的SpringBoot框架入门教程

    Spring Boot 框架快速入门教程以大量示例讲解了 Spring Boot 在各类情境中的应用,让大家可以跟着老师的思维和代码快速理解并掌握。适用于 Java 开发人员,尤其…

    技术杂谈 2023年7月25日
    068
  • 分布式理论—-CAP理论与Base理论

    CAP 理论 【1】CAP 理论指出对于一个分布式计算系统来说,不可能同时满足以下三点: 1)一致性:在分布式环境中,一致性是指数据在多个副本之间是否能够保持一致的特性,等同于所有…

    技术杂谈 2023年7月23日
    069
  • Java编程基础(整理)

    Java教程官方文档: JDK11官方文档: 《Java编程思想》学习笔记: 《Java从入门到精通》学习笔记: 软件开发:系统软件、应用软件 人机交互:GUI(图形化界面)、CL…

    技术杂谈 2023年7月11日
    050
  • 浅谈IT系统性能优化

    一个刚上线的IT系统,往往负载压力不大,所以不会存在什么性能问题。这时,人们大多只关心系统的功能性和用户体验。但是,随着时间推移,用户量和数据量都比刚上线的时候要多很多,高并发和大…

    技术杂谈 2023年7月11日
    056
  • 导航规划之CH算法介绍

    1 CH算法的基本原理 CH(Contraction Hierarchies)算法是 Robert Geisberger、Peter Sanders、Dominik Schulte…

    技术杂谈 2023年5月31日
    0112
  • 【Golang】golang中map元素的删除和清空

    当我们想把一个map元素完全清空的时候 可以直接赋值一个新的map过去就可以了,Go语言中并没有为 map 提供任何清空所有元素的函数、方法,清空 map 的唯一办法就是重新 ma…

    技术杂谈 2023年6月1日
    0101
  • html大文件传输方案

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用。 首先我们需要了解的是上传文件三要素: 1.表单提交方式:post (…

    技术杂谈 2023年5月30日
    066
  • html大文件传输方法

    IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头。 一. 两个必要响应头Accept-Ranges、ETag 客户端每次…

    技术杂谈 2023年5月30日
    075
  • 基于图像识别框架Airtest的Windows项目自动化测试实践

    写在前面 上一篇分享了《基于Sikuli GUI图像识别框架的PC客户端自动化测试实践》,但sikuli看起来怎么都像是上个世纪的界面风格,且功能过于简陋。而同样基于图像识别框架的…

    技术杂谈 2023年7月25日
    082
  • Mybatis源码1JDBC->mybatis主要流程->mybatis Excutor简介

    === 一丶mybatis概述 MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获…

    技术杂谈 2023年7月25日
    069
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球