一、B 树是一种多叉平衡查找树

相较于二叉结构的红黑树,B 树是多叉结构,所以在元素数量非常多的情况下,B 树的高度不会像二叉树那么大,从而保证查询效率。

一棵含 n 个结点的 B 树的高度 h = O(logtn),其中 t 是 B 树的最小度数。

  • 提出多叉平衡查找树的思维历程:查询效率要更高 ----> 查询次数要更少 ----> 查找树的高度要更低 ----> 每个结点保存的信息要更多 ----> 多叉

下图是一棵B树的示意图:

二、B 树的定义

《算法导论》中用最小度数 t 来定义 B 树,所谓最小度数,即结点拥有的最小孩子数。

一棵最小度数为 t 的 B 树是满足如下四个条件:

  1. 每个非根结点至少含有 t - 1 个关键字,根结点至少含有 1 个关键字
  2. 每个结点至多含有 2t - 1 个关键字,即一个结点至多可有 2t 个孩子(如果一个结点恰好有 2t - 1 个关键字,我们就说这个结点是满的)
  3. 一个结点 u 中的关键字按非降序排列,如u.key≤ u.key≤ … ≤ u.keyn-1
  4. 每个节点的关键字对其子树的范围分割,设节点 u 有 n + 1 个指针,指向其 n + 1 棵子树,指针为u.p0, u.p1, u.p2, …, u.pn,关键字 ki 为 u.pi 所指的子树中的关键字,有 k≤ u.key0 ≤ k1 ≤ u.key ≤ u.keyn-1 ≤ kn 成立
  5. 所有叶子结点具有相同的深度,即树的高度 h(这表明了 B 树是平衡的)
/* B树结点结构 */
struct BTreeNode {
int keyNum; // 关键字的数目
BTreeNode *parent; // 指向父结点
BTreeNode **ptr; // 子树指针向量:ptr[0]...ptr[keyNum]
KeyType *key; // 关键字向量;key[0]...key[keyNum-1]
};

三、查询操作

例题:一棵已经建立好的B树如下图所示,要求查找关键字为29的文件。

  • 结点中的关键字表示磁盘文件的文件名,而小红块表示对应的关键字所代表的文件在硬盘中的存储位置,P是指针
  • 指针、关键字以及关键字所代表的文件地址合起来构成了B树的一个结点,这个结点存储在一个磁盘块上

  • 假如每个磁盘块正好可以存放一个B树的结点(正好存放2个文件名)。那么一个B树结点就代表一个盘块,而子树指针就是存放另外一个盘块的地址

搜索过程如下:

  1. 从根结点开始,读取根结点信息,根结点有2个关键字:17和35。因为17 < 29 < 35,所以找到指针P2指向的子树,也就是磁盘块3(1次I/0操作)

  2. 读取当前结点信息,当前结点有2个关键字:26和30。因为26 < 29 < 30,所以找到指针P2指向的子树,也就是磁盘块8(2次I/0操作)

  3. 读取当前结点信息,当前结点有2个关键字:28和29。找到了!(3次I/0操作)

由上面的过程可见,同样的操作,如果使用平衡二叉树,那么需要至少4次 I/O 操作,而且这种优势还会随着结点数的增加而更加明显。另外,因为 B 树结点中的关键字都是排好序的,所以,在结点中的信息被读入内存之后,可以采用二分查找这种快速的查找方式,更进一步减少了读入内存之后的计算时间。由此可见,对于外存数据结构来说,I/O操作的次数是其查找信息中最大的时间消耗,而我们要做的所有努力就是尽量在搜索过程中减少I/O操作的次数。

如何理解“树的高度过大而造成磁盘I/O读写过于频繁,进而导致查询效率低下”这句话?

在大规模数据存储方面,大量数据存储在外存磁盘中,而在外存磁盘中读取/写入块(block)中某数据时,首先需要定位到磁盘中的某磁盘块。

磁盘读取数据是以盘块(block)为基本单位的。位于同一盘块中的所有数据都能被一次性全部读取出来。而磁盘I/O代价主要花费在盘块查找时间T上。因此我们应该尽量将相关信息存放在同一盘块,同一磁道中。或者至少放在同一柱面或相邻柱面上,以求在读/写信息时尽量减少磁头来回移动的次数,避免过多的查找时间T。

因此,使用B树使得树的高度更低,从而需要查找的盘块也就更少(即减少磁盘I/O操作的次数),所需的盘块查找时间也就越低,查询效率自然提高。

四、插入/删除操作

参考博客:B树&B+树B树与B+树

6. B树的更多相关文章

  1. B树——算法导论(25)

    B树 1. 简介 在之前我们学习了红黑树,今天再学习一种树--B树.它与红黑树有许多类似的地方,比如都是平衡搜索树,但它们在功能和结构上却有较大的差别. 从功能上看,B树是为磁盘或其他存储设备设计的, ...

  2. ASP.NET Aries 入门开发教程8:树型列表及自定义右键菜单

    前言: 前面几篇重点都在讲普通列表的相关操作. 本篇主要讲树型列表的操作. 框架在设计时,已经把树型列表和普通列表全面统一了操作,用法几乎是一致的. 下面介绍一些差距化的内容: 1:树型列表绑定: v ...

  3. 再讲IQueryable<T>,揭开表达式树的神秘面纱

    接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...

  4. HDU1671——前缀树的一点感触

    题目http://acm.hdu.edu.cn/showproblem.php?pid=1671 题目本身不难,一棵前缀树OK,但是前两次提交都没有成功. 第一次Memory Limit Exceed ...

  5. 算法与数据结构(十一) 平衡二叉树(AVL树)

    今天的博客是在上一篇博客的基础上进行的延伸.上一篇博客我们主要聊了二叉排序树,详情请戳<二叉排序树的查找.插入与删除>.本篇博客我们就在二叉排序树的基础上来聊聊平衡二叉树,也叫AVL树,A ...

  6. [C#] C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  7. bzoj3207--Hash+主席树

    题目大意: 给定一个n个数的序列和m个询问(n,m<=100000)和k,每个询问包含k+2个数字:l,r,b[1],b[2]...b[k],要求输出b[1]~b[k]在[l,r]中是否出现. ...

  8. bzoj1901--树状数组套主席树

    树状数组套主席树模板题... 题目大意: 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[ ...

  9. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  10. jquery-treegrid树状表格的使用(.Net平台)

    上一篇介绍了DataTable,这一篇在DT的基础之上再使用jquery的一款插件:treegrid,官网地址:http://maxazan.github.io/jquery-treegrid/ 一. ...

随机推荐

  1. angular路由传参和获取路由参数的方法

    1.首先是需要导入的模块 import { Router } from "@angular/router";//路由传参用到 import{ActivatedRoute,Param ...

  2. ueditor getshell漏洞重现及分析

    0x00 概述 8月21日,网上爆出ueditor .net版本getshell漏洞,由于只校验ContentType而没校验文件后缀导致getshell. 0x01 漏洞重现 Payload: &l ...

  3. C++ primer第三章作业

    3.1节 练习3.1: 使用恰当的using声明重做1.4.1节(第11页)和2.6.2节(第67页)的练习 #ifdef 1 #include <iostream> using std: ...

  4. zabbix3.0通过yum安装笔记

    zabbix3.0通过yum安装笔记 一.通过yum安装zabbix rpm -Uvh https://repo.zabbix.com/zabbix/3.0/rhel/7/x86_64/zabbix- ...

  5. MySQL案例04:Cause: java.sql.SQLException: Could not retrieve transaction read-only status from server

    今天同事发现程序日志有异常抛出,询问原因,进过排查发现与java的连接参数有关系,具体处理过程如下: 一.错误信息 "message": "\n### Error upd ...

  6. 全局变量和局部变量(global关键字)

    1.定义在函数外部的就是全局变量,它的作用域从定义处一直到文件结尾. 2.函数内定义的变量就是局部变量,它的作用域为函数定义范围内. 3.函数之间存在作用域互不影响. 4.函数内访问全局变量需要 gl ...

  7. [试玩] FMXLinux (Firemonkey for Linux) Linux 桌面开发(第三方插件)

    FMXLinux 是一个可以用来开发 Linux 桌面软件的第三方插件,它需要配合 Delphi 10.2 Toyko 官网:http://www.fmxlinux.com/ 使用方法:开启 FMX ...

  8. 运行TensorFlow报错,“This program requires version 3.6.1 of the Protocol Buffer runtime library, but the installed version is 3.0.0.”

    报错信息: [libprotobuf FATAL google/protobuf/src/google/protobuf/stubs/common.cc:67] This program requir ...

  9. django的数据库操作-16

    目录 增 1.save 2.create 查 1.基本查询 2.过滤查询 3. F对象 4. Q对象 5. 聚合函数 6. 排序 7. 关联查询 8. 关联+过滤查询 删 改 1. save 2. u ...

  10. Nginx部署tomcat/wildfly集群负载均衡

    1.调度器配置: docker run -p 80:80 --name nginx --restart=always  -v /root/nginx/www/:/usr/share/nginx/htm ...