首页 文章 精选 留言 我的

精选列表

搜索[图像理解],共10001篇文章
优秀的个人博客,低调大师

理解 B+树

B+树是为磁盘和存储工具设计的一种数据结构,它是一种平衡查找树,它在查找,插入、修改方面的时间复杂度都稳定为 O(logn) 节点 图(1) B+树节点是一组按照key有序的元素,B+树包含两种类型的节点,一种是索引节点,一种是叶子节点 索引节点也叫内部节点,索引节点只包含key,不包含data, 节点的 key是升序排列的,对于指定的索引节点key来说,它左子树上所有的key都小于它的key,它右子树上所有的key都大于等于它的key 叶节点上存储的是主键和数据(key和data), 所有的叶节点都在同一高度上,节点按key 从小到大并且通过指针使得彼此链接,这样,所有的叶节点组成了一个双向有序链表,叶节点这样做的好处是在不访问索引的情况下能顺序检索数据,也能很好的支持范围查询的快处理 B+树特点 阶数为 m 的B+树,每个索引节点最多有 m 个子节点,每个索引节点页面最多存储 m - 1 个索引key 所有索引节点的子节点数在 Math.ceil(m / 2) 和 m 之间 B +树之所以称为平衡树,是因为从根节点到叶节点的每条路径都具有相同的长度。平衡树意味着所有对单个值的搜索都需要从磁盘读取相同数量的页面。 填充因子 B+树使用填充因子来控制页面的分裂和合并,设置数据占用页面空间的百分比,目的是为后面的数据预留一部分页空间,当有新数据时,可以放到预留的页空间中,避免分页的发生 默认的填充因子是50%,对于一棵m阶的B+树,填充因子是 m/2 B+树操作 B+树常用操作涉及到查询、插入、删除、范围查询, 为了便于说明,下面所有操作的例子中的B+树无特殊说明都是5阶树 每个页面最多有4个key,大于等于5个时就需要分裂或者旋转合并 填充因子默认是50%,页面中已经使用了的数量为2表示填充因子为50%,同理,小于2时候表示填充因子小于50%,大于2时候表示填充因子大于50% 查询 B+树的索引节点是有序的,查询单个key的话直接用二分查找定位到目标叶子页面,在目标叶子页面中顺序遍历,找到目标key,则返回叶子页面中目标key对应的数据 插入 B+树的插入操作完成以后,有以下几种情况 1. 叶节点和索引节点没有满 这种情况插入操作步骤最少,根据key把数据插入到叶节点已经排序的位置上即可,下图中是插入key为 23的数据,23会插入到包含15, 21的叶子页面中,插入之后叶子页面没有满,不用处理页面分裂的情况 2. 叶节点满了,索引节点未满 步骤:(1):叶子页面分裂成两个页面(2): 把中间行数据的key按顺序加入到上一层的索引页中(3): 所有小于中间行数据key的数据放到左叶子页面(4): 所有大于等于中间行数据key的数据放到右叶子叶面 图(2) 往图(2) 的B+树中插入key为28的数据,这条数据会插入到包含15,21,23,27的叶子页面中,插入之后,该页面数据已满,必须要分裂成如下所示的两个页面: 左叶子页面 右叶子页面 15,21 23,27,28 中间行数据key为:23,放到上一层的索引页面中15的后面,下面图(3)是插入key为28的结果 图(3) 3. 叶子页面和索引页面都满了 步骤:(1):叶节点页面分裂成左右两个叶子页面(2): 把中间行数据的key按顺序加入到索引页中(3): 所有小于中间行数据key的数据放到左叶子页面(4): 所有大于等于中间行数据key的数据放到右叶子页面(5): 上面步骤(2)执行之后,索引页面满了,分裂成左右两个索引页(6): 所有小于索引页中间的key的放到左边索引页(7): 所有大于索引页中间的key的放到右边索引页(8): 把索引页中间的key放到更高一层的索引页如果步骤(8)执行之后,更高一层的索引页满了,继续执行(5)-(8)步骤 图(4) 图(4) 的B+树插入key为30的数据,这条数据会插入到23, 27, 28, 29的叶子页面中,插入之后,该页面数据已满,必须要分裂成如下所示的两个页面: 左叶子页面 右叶子页面 23,27 28,29,30 中间行数据key为:28,放到索引页面中23 的后面 28 放到索引页面23的后面之后,索引页变成了4, 7, 15, 23, 28, 这时索引页也满了,分裂成如下所示的三个页面 : 左索引页 右索引页 更高一层索引页 4,7 23,28 15 下面图(5)为插入key为30数据之后,叶子页面和索引页面分裂之后的结果: 图(5) 旋转 B+树的插入操作会有页面分裂的情况,页面分裂就会有产生磁盘IO,相对内存,磁盘 IO 要慢得多,所以为了减少磁盘IO操作,就要尽可能的减少页面分裂,充分利用页面空间,因此B+树提供了旋转操作 旋转操作的应用场景: B+树叶子页面空间已经满了,但是它的左右兄弟页面没有满 叶子页面空间满了,B+树会优先检查左右兄弟叶子页面是否能容纳数据,当左右兄弟页面空间都满了时,才会考虑页面分裂 图(6) 图(6)中,插入key为12的数据,叶子页面空间满了,这时B+树先检查左兄弟页面是否有多余的空间,通过旋转,把key分别为7, 10, 11, 12, 13的叶子中的 7 移动到左兄弟页面中,移动完成之后,左兄弟的key变成了2, 5, 7 同时,叶子中key为7的数据在上层索引页中也有记录,所以需要把上层索引页中key为7修改为 10,修改之后上层索引key分别为10, 15,最终的结果如下图(7)所示 图(7) 叶子页面插入新数据之后,页面空间已满,原本页面是需要分裂的,但是通过把当前页面上的数据移动到能容纳数据的兄弟页面中,减少了一次页分裂,也即减少了一次磁盘IO操作 删除 B+树的删除操作完成以后,有以下几种情况 1. 叶子页面和索引页面填充因子都大于等于50% 这种情况直接删除节点,页面会把删除节点的位置标记为空,以便存放后续其他的数据,同时,如果删除的key出现在上层的索引页面中,需要用叶子页面中被删除节点的下一个节点key去替换它 图(8) 图(8)中 7是待删除的节点,删除7后,叶子页面填充因子刚好等于50%,因为被删除的7在上层的索引页面中出现了相同的key,所以需要用叶子页面中下一个key,也就是12替换上层索引页面中的7,最终的结果如下面图(9)所示: 图(9) 2. 叶子页面填充因子50%,索引页面填充因子大于等于50% 叶子页面填充因子小于50%的时候,为了维持B+树的平衡,会有页面数据转移和合并的操作 从兄弟页面转移key数据到当前页面 当一个叶子页面填充因子小于50%,左右兄弟页面存在填充因子大于50%的时候,可以把兄弟页面中的数据转移到当前页面中,上一层索引页面中因叶子页面数据转移受影响的索引key也需要做相应的处理 如果左右兄弟页面的填充因子都大于50%时,转移任何一边页面数据到当前页面都可以,虽然选择不同的页面转移数据后,B+树的形态不一样,但是最终都是满足B+树特点的 图(10) 上面图(10)中,删除key为16的数据 ( 图中红色标识的区域 ),删除之后,原来key为15, 16的叶子页面变成了15,页面只剩下一个key 此时页面的填充因子小于50%,左兄弟页面填充因子大于50%,满足页面数据转移的条件 把左兄弟页面 (key为7, 12, 13)中的 13 转移到当前页面中 转移之后,两个页面key数量刚好等于填充因子,左兄弟页面key变为7, 12,当前页面的key变为13, 15 当前页面中最小key值由原来的 15 变成了 13,为了保持B+数的平衡,需要把当前页面上一层的索引页面中key为15替换为13, 最终的结果如下面图(11)所示 : 图(11) 当前页面key合并到兄弟页面 上面说明了从兄弟页面转移数据到当前页面,现在我们来看下当前页面数据量小于填充因子的时候,如何合并到兄弟页面中 当一个叶子页面填充因子小于50%,左右兄弟页面存在填充因子等于50%的时候,可以把这个叶子页面合并到左右兄弟页面中,上一层索引页面中因叶子页面数据合并受影响的索引key也需要做相应的处理 图(12) 在图(12)中,执行删除key为15的操作(图中红色区域),15位于key为13, 15的页面中,删除15之后,当前页面key变成了13, 只剩下一个key了 此时,当前页面填充因子小于50%,左右兄弟节点填充因子等于50%,所以无法从兄弟页面转移key数据到当前页面,但满足当前页面数据合并到兄弟页面的条件 左右兄弟页面都满足当前页面数据合并过去,选择任一兄弟页面都可以,虽然选择不同兄弟页面,会导致B+树的形态也不一样,但最终都是让B+树维持平衡,这里我们选则合并到左兄弟页面 15 被删除了之后,当前页面只剩下key为13的数据了 它合并到左兄弟页面之后, 当前页面为空,需要移除上一层索引页面中指向当前页面的索引key 13, 移除13的索引key之后, 索引页面key由原来的7, 13, 23变成7, 23 合并之后,左兄弟页面key由原来的7, 12变成7, 12, 13 最终的结果如下面 图(13) 所示 : 图(13) 3. 叶子页面和索引页面填充因子都小于50% 当叶子页面和索引页面填充因子都小于50%的时候,叶子页面和索引页面都会有数据转移或者合并的操作 图(14) 在图(14)中,执行删除叶子页面中key为12的数据(图中红色区域),12 位于key为7, 12叶子页面中,删除 12 之后,当前叶子页面变成了7,只剩下一个key了 当前叶子页面左右兄弟页面填充因子都是50%,所以满足合并的条件,合并到左兄弟页面或右兄弟页面都可以,这里我们选择合并到左兄弟页面 当前叶子页面中key为 7 的数据合并到左兄弟页面之后,当前叶子页面没数据了,而左兄弟页面key变成了2, 5, 7 为了保持B+树的平衡,指向当前叶子页面的上一层索引页面中,需要删除key为 7 的索引key, 删除key为7的索引后,索引页面key变成了15, 这时该索引页面填充因子小于50%,右兄弟页面填充因子等于50%,满足合并的条件 但是,索引页面数据合并到右兄弟页面之后,根节点的左子树就为空了,为了保持B+树的平衡,根页面数据需要合并到下一层的索引页面中 最后的结果如下面图(15)所示 : 图(15) 范围查询 B+树的叶子节点是按照key从小到大的顺序组成的一个双向链表,所以B+树非常适合范围查询(这里说的范围是B+树中索引节点的key的范围) 使用二分查找首先确定范围查询的起始key所在的叶子节点的位置,然后顺序遍历叶节点链表,直到叶节点key大于范围查询结束key,查询停止 B+树的大小 一颗 m 阶的B+树,索引节点存储的是索引信息,为了计算方便,这里假设一个索引key信息 8 字节,一个磁盘页面大概 4KB,那么一个磁盘页面能容纳的索引数量为:4 * 1024 / 8 = 512,此时 m 就等于 512 当B+树高度为2时,最多能容纳 512 (512的1次方) 个索引信息 当B+树高度为3时,最多能容纳 26万 (512的2次方)个索引信息 当B+树高度为4时,最多能容纳 1.3亿 (512的3次方)个索引信息 当B+树高度为5时,最多能容纳 687亿 (512的4次方)个索引信息 从上面的数据可以看到,B+树高度为5时, 能容纳 687 亿个索引信息,可以非常够用了 在实际的应用当中,B+树的根节点都是缓存在内存中的,树的最底层是叶子节点 所以针对高度为5的B+树,查找一条指定key值的数据最多只需要3次磁盘IO就能定位到具体的叶子页面,当树高度为4时,最多只需要2次磁盘IO就能定位到具体的叶子页面 B+树的应用 B+树主要用于磁盘和存储工具,著名的MySQL引擎 InnoDB 索引的数据模型使用的就是 B+ 树 当数据超过一定的量级的时候,为了快速检索数据而设置的索引信息也会变得非常庞大,而且这部分索引信息只能存储在磁盘中,B+树能从磁盘中快速检索到需要的数据,并且时间复杂度稳定在O(logn) 本文分享自微信公众号 - Linux开发那些事儿(LinuxThings)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

python unittest框架理解

整个平台的搭建使用的是python的unittest测试框架,这里简单介绍下unittest模块的简单应用。 unittest是python的标准测试库,相比于其他测试框架是python目前使用最广的测试框架。 Unittest framework 正常调用unittest的流程是: 1、TestLoader 自动将测试用例TestCase中加载到TestSuite里 2、在执行TestCase过程中,先进行SetUp()环境准备,执行测试代码。 3、TextTestRunner调用TestSuite的run方法,顺序执行里面的TestCase中以test开头的方法,其中TestLoader在加载过程中,进行添加的TestCase是没有顺序的。一个TestCase里如果存在多个验证方法的话,会按照方法中test后方首字母的排序进行执行。可以通过手动调用TestSuite的addTest、addTests方法来动态添加TestCase,这样既可以确定添加用例的执行顺序,也可避免TestCase中的验证方法一定要用test开头。 4、最后tearDown()进行测试的还原。 5、得到测试结果TestResult。 KeywordsTestCase: The individual unit of testing.TestSuite: A collection of test cases, test suites, or both. It is used to aggregate tests that should be executed together.TestLoader: Load the test cases to the test suite.TestRunner: A component which orchestrates the execution of tests and provides the outcome to the user.TestFixture: Represents the preparation needed to perform one or more tests, and any associate cleanup actions. setUp(), tearDown(), setUpClass(), tearDownClass()Decorator: skip, skipIf, skipUnless, expectedFailure unittest有四个比较重要的概念是test fixture, test case, test suite, test runner, 。 test fixture:The test fixture is everything we need to have in place to exercise the sut。简单来说就是做一些测试过程中需要准备的东西,比如创建临时的数据库,文件和目录等,其中 setUp() 和 setDown() 是最常用的方法 test case:用户自定义的测试case的基类,调用run()方法,会依次调用setUP方法、执行用例的方法、tearDown()方法。 test suite:测试用例集合,可以通过addTest()方法手动增加Test Case,也可通过TestLoader自动添加Test Case,TestLoader在添加用例时,会没有顺序。 test runner:运行测试用例的驱动类,可以执行TestCase,也可执行TestSuite。执行后TestCase和Testsuite会自动管理TestResult。 Command linepython -m unittest xxxpython -m unittest -hpython -m unittest discover # discovery the test cases(test*.py) and execute automatically

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册