6. B树
一、B 树是一种多叉平衡查找树
相较于二叉结构的红黑树,B 树是多叉结构,所以在元素数量非常多的情况下,B 树的高度不会像二叉树那么大,从而保证查询效率。
一棵含 n 个结点的 B 树的高度 h = O(logtn),其中 t 是 B 树的最小度数。
- 提出多叉平衡查找树的思维历程:查询效率要更高 ----> 查询次数要更少 ----> 查找树的高度要更低 ----> 每个结点保存的信息要更多 ----> 多叉
下图是一棵B树的示意图:
二、B 树的定义
《算法导论》中用最小度数 t 来定义 B 树,所谓最小度数,即结点拥有的最小孩子数。
一棵最小度数为 t 的 B 树是满足如下四个条件:
- 每个非根结点至少含有 t - 1 个关键字,根结点至少含有 1 个关键字
- 每个结点至多含有 2t - 1 个关键字,即一个结点至多可有 2t 个孩子(如果一个结点恰好有 2t - 1 个关键字,我们就说这个结点是满的)
- 一个结点 u 中的关键字按非降序排列,如u.key1 ≤ u.key2 ≤ … ≤ u.keyn-1
- 每个节点的关键字对其子树的范围分割,设节点 u 有 n + 1 个指针,指向其 n + 1 棵子树,指针为u.p0, u.p1, u.p2, …, u.pn,关键字 ki 为 u.pi 所指的子树中的关键字,有 k0 ≤ u.key0 ≤ k1 ≤ u.key1 … ≤ u.keyn-1 ≤ kn 成立
- 所有叶子结点具有相同的深度,即树的高度 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树结点就代表一个盘块,而子树指针就是存放另外一个盘块的地址
搜索过程如下:
从根结点开始,读取根结点信息,根结点有2个关键字:17和35。因为17 < 29 < 35,所以找到指针P2指向的子树,也就是磁盘块3(1次I/0操作)
读取当前结点信息,当前结点有2个关键字:26和30。因为26 < 29 < 30,所以找到指针P2指向的子树,也就是磁盘块8(2次I/0操作)
读取当前结点信息,当前结点有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操作的次数),所需的盘块查找时间也就越低,查询效率自然提高。
四、插入/删除操作
6. B树的更多相关文章
- B树——算法导论(25)
B树 1. 简介 在之前我们学习了红黑树,今天再学习一种树--B树.它与红黑树有许多类似的地方,比如都是平衡搜索树,但它们在功能和结构上却有较大的差别. 从功能上看,B树是为磁盘或其他存储设备设计的, ...
- ASP.NET Aries 入门开发教程8:树型列表及自定义右键菜单
前言: 前面几篇重点都在讲普通列表的相关操作. 本篇主要讲树型列表的操作. 框架在设计时,已经把树型列表和普通列表全面统一了操作,用法几乎是一致的. 下面介绍一些差距化的内容: 1:树型列表绑定: v ...
- 再讲IQueryable<T>,揭开表达式树的神秘面纱
接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...
- HDU1671——前缀树的一点感触
题目http://acm.hdu.edu.cn/showproblem.php?pid=1671 题目本身不难,一棵前缀树OK,但是前两次提交都没有成功. 第一次Memory Limit Exceed ...
- 算法与数据结构(十一) 平衡二叉树(AVL树)
今天的博客是在上一篇博客的基础上进行的延伸.上一篇博客我们主要聊了二叉排序树,详情请戳<二叉排序树的查找.插入与删除>.本篇博客我们就在二叉排序树的基础上来聊聊平衡二叉树,也叫AVL树,A ...
- [C#] C# 知识回顾 - 表达式树 Expression Trees
C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...
- bzoj3207--Hash+主席树
题目大意: 给定一个n个数的序列和m个询问(n,m<=100000)和k,每个询问包含k+2个数字:l,r,b[1],b[2]...b[k],要求输出b[1]~b[k]在[l,r]中是否出现. ...
- bzoj1901--树状数组套主席树
树状数组套主席树模板题... 题目大意: 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[ ...
- bzoj3932--可持久化线段树
题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...
- jquery-treegrid树状表格的使用(.Net平台)
上一篇介绍了DataTable,这一篇在DT的基础之上再使用jquery的一款插件:treegrid,官网地址:http://maxazan.github.io/jquery-treegrid/ 一. ...
随机推荐
- Java并发编程(九)线程间协作(下)
上篇我们讲了使用wait()和notify()使线程间实现合作,这种方式很直接也很灵活,但是使用之前需要获取对象的锁,notify()调用的次数如果小于等待线程的数量就会导致有的线程会一直等待下去.这 ...
- Vue如何循环渲染图片
Vue如何把服务器返回的图片数据渲染出来 首先,一般来说,当请求图片的接口时,会返回一个数组,这个数组里会是一些图片的名字,比如1.jpg,2.jpg. 我的做法是先在data里定义一个数组,来存储服 ...
- C++的六个函数
一.构造函数 在C++中,构造函数是六个函数中的第一个,当一个对象被创建时,在它的整个周期中,是一个由生到死的 过程,即构造函数创建对象,析构函数析构对象.在对象被创建时,调用构造函数创建一个对象,这 ...
- encodeURIComponent编码反斜杠 \ (正则匹配)
记录一个小bug... 前言废话: 1. 功能需求:修改输入框的内容,获取字符串传给后端保存. 2. bug历程:刚开始直接获取value值传过去.后来测试发现%&这些特殊字符无法传递后,在前 ...
- python面试题之基础2
2.3 考虑以下 Python 代码,如果运行结束,命令行中的运行结果是什么? 两者用法相同,不同的是 range 返回的结果是一个列表,而 xrange 的结果是一个生成器,前者是 直接开辟一块内存 ...
- Redis的特性以及优势(附官网)
NoSQL:一类新出现的数据库(not only sql) 泛指非关系型的数据库 不支持SQL语法 存储结构跟传统关系型数据库中的那种关系表完全不同,nosql中存储的数据都是KV形式 NoSQL的世 ...
- 安装xml2js出现npm ERR! code E404 npm ERR! 404 Not Found: event-stream@3.3.6
原因是npm源指向的问题 执行: npm config set registry https://registry.npmjs.org/
- 20155334 实验二 Java面向对象程序设计
实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验要求 完成实验.撰写 ...
- ruby学习笔记(3)- 新手入门
这里是一个Ruby开发的快速参考指南: Ruby是什么 ? Ruby是一种纯粹的面向对象编程语言.它由日本松本幸创建于1993年. Ruby是一种通用的解释编程语言如Perl和Python. IRb是 ...
- 【转载】C/C++杂记:深入理解数据成员指针、函数成员指针
原文:C/C++杂记:深入理解数据成员指针.函数成员指针 1. 数据成员指针 对于普通指针变量来说,其值是它所指向的地址,0表示空指针.而对于数据成员指针变量来说,其值是数据成员所在地址相对于对象起始 ...