B树(B+树) 学习总结

一,B树的定义及介绍

为什么会有B树?

熟悉的树的结构有二叉树查找树或者平衡二叉树……平衡二叉树保证最坏情况下各个操作的时间复杂度为O(logN),但是为了保持平衡,在插入或删除元素时,需要进行旋转啊...一系列操作,因此实现起来比较复杂。而对于二叉查找树,基本操作在最坏情况下会出现O(N)的时间复杂度。总之,这些树都是针对于内存中的数据操作,它们每个结点最多只有两个孩子,当数据量大时(结点数目很多),就会导致树很高。但由于基本操作(查找元素、插入元素)都是在内存中实现,因此,树高点也就没有太大的关系。

试想,如果树中的结点数据 是存储在磁盘上的,每访问一个结点需要进行一次磁盘的读取操作,那么树的高度就很重要了。因为,磁盘访问的代价(速度)远远大于内存访问的代价。对于7200转的硬盘而言,访问一次磁盘大约需要8.3ms,而对于4GHz的CPU而言,8.3ms不知可以执行多少次指令了。

因此,B树一个很重要的特征就是:高度小。

那如何让高度变小呢?让每个结点可以拥有多个(远远大于2)孩子就可以了。但是,为了在插入、删除中仍然保持B树的性质(比如高度要低),还需要对B树做一些其他方面的规定:(实际实现过程中可能不同)。

其中最重要的规定是:每个结点最多包含多少个关键字(项),最少需要包含多少个关键字。

这里,给出一个具体的M阶 B树定义(《数据结构与算法分析》MAW著)

①数据项 只存储在树叶上。(数据项就是实实在在的数据,而不是索引)

②非叶子结点最多可以 存储 M-1个关键字以指示搜索的方向(这里的关键字是指索引)。

这里的M-1个关键字是按从小到大的顺序排序的。M-1个关键字,就有M个指针,指向进一步查找的路径。

③树的根或者是一片树叶,或者其儿子数在 2 到 M之间

④除根外,所有非树叶节点的儿子数在 【M/2】 和 M 之间   【M/2】表示,M/2并向上取整

非叶子结点的儿子数最少为【M/2】,这就是为了保证每个结点足够多的孩子,从而使树的高度不至于太大。

⑤所有的树叶都在相同的深度上并有【L/2】 和 L 个数据项

这里表明,真正的数据只存储在叶子结点上。非叶子结点只存储索引。

在上面的具体规定中,M 和 L 是如何确定的呢?

M 和 L的确定与磁盘块的大小相关。对于B树而言,每个结点都尽量占据一个磁盘块。

比如,假设有 1千万数据项,每个关键字(索引)是32B,而每个数据项是256B,磁盘块的大小是8192B,如何确定M 和 L 呢?

由于M阶B树中,每个结点最多有 M-1 个关键字,故关键字总大小为 32M-32,M-1个关键字最多有M个分支指针,假设每个分支指针是4B(字节),故分支指针

的大小是4*M个字节。那么对于一个非叶子结点,它的大小是36*M-32 字节,由于磁盘块大小是8192,故M = 8192/(36*M-32) = 228

由上面的第5点可知,叶子结点只存储数据项,每个数据项大小为256B,故 L=8192/256=32,这说明每个叶子结点可以存储32个数据项。

M 与关键字以及指针的大小有关,而L与数据项的大小有关。总之,目标是:不管是叶结点还是非叶结点,都尽量保证一个结点占据一个磁盘块。

二,B树的基本操作

1)查找操作

查找操作的伪代码如下:《算法导论》这里的B树中数据项可存储在非叶子结点上。

 1 B-TREE-SEARCH(x,k)
 2     i = 1
 3     while i<= M‘ and k > key(i)
 4           i++
 5     if i<=M‘ and k=key(i)
 6           return (x,i)
 7     if leaf(x)
 8           return NIL
 9     else
10          DISK-READ(child(x(i)))
11          return B-TREE-SEARCH(child(x(i)),k)

x实际上代表根结点。第3行,扫描结点上所有的数据项看是否与k匹配,若不匹配且结点不是叶子结点,则需要在第10行进行一次磁盘读取操作,将该结点中某数据项指向的孩子结点读入内存,再进行比较。

2)插入操作

插入操作可能会导致结点分裂。插入操作的具体实现细节可能与这里描述的不一样。

比如,向一个已经满了的叶结点插入一个数据项时,该叶结点分裂成两个结点,并将中间数据项上移到该结点的双亲结点。

3)删除操作

删除操作可能会导致结点合并。具体描述参考算法导论。

比如,还可以这样来处理:当某个节点不包含的数据项已经达到最小时,可以从邻节点 “领养” 一个数据项。当邻节点也不足时,则将这两个节点合并成一个节点。

三,B树与B+树的主要区别

最主要的区别就是:B树中非叶子结点可以存储数据,而B+树非叶子结点只存储索引,所有的数据都放在叶子结点上存储。

参考:B树学习总结

时间: 2024-12-31 04:02:43

B树(B+树) 学习总结的相关文章

树链剖分学习笔记

先让我们看一个题目 有一棵n个节点的树,树的每条边有个边权,有如下两种操作 1.修改一条边的边权 2.查询两点之间路径的权值 对于这种题目,可能有人会选择直接暴力,这很明显不行. 换一种思路,如果我们把树的每一条边拆下来,对他们进行编号,然后使用线段树来存储呢?使用线段树来对每条边的边权进行修改和查询是很方便的.于是这样我们就引出了树链剖分. 树链剖分其实就是把一棵树上的各个边拆开来进行处理,从而对树的整体进行划分. 将树划分为链,用数据结构来维护这些链,时间复杂度大致为O(log n) . 在

外排序 &amp; 败者树 &amp; 多路归并-学习

来来来,根据这篇文章,学一下败者树吧: http://blog.csdn.net/whz_zb/article/details/7425152 一.胜者树 胜者树的一个优点是,如果一个选手的值改变了,可以很容易地修改这棵胜者树.只需要沿着从该结点到根结点的路径修改这棵二叉树,而不必改变其他比赛的结果. 二.败者树 败者树是胜者树的一种变体.在败者树中,用父结点记录其左右子结点进行比赛的败者,而让胜者参加下一轮的比赛.败者树的根结点记录的是败者,需要加一个结点来记录整个比赛的胜利者.采用败者树可以

树链剖分学习&amp;BZOJ1036

题目传送门 树链剖分,计算机术语,指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结构(树状数组.SBT.SPLAY.线段树等)来维护每一条链. 以下是几种概念: 常见的路径剖分的方法是轻重树链剖分(启发式剖分) 将树中的边分为:轻边和重边 ?定义size(X)为以X为根的子树的节点个数. ?令V为U的儿子节点中size值最大的节点,那么边(U,V)被称为重边,树中重边之外的边被称为轻边. 性质:?轻边(U,V),size(V)<=size

【学习总结】数据结构-Trie/前缀树/字典树-及其最常见的操作

Trie/前缀树/字典树 Trie (发音为 "try") 或前缀树是一种树数据结构,用于检索字符串数据集中的键. 一种树形结构,是一种哈希树的变种. 典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计. 优点:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高. 应用: 自动补全 END 原文地址:https://www.cnblogs.com/anliux/p/12590368.html

《数据结构与算法分析:C语言描述》复习——第四章“树”——AVL树

2014.06.15 16:22 简介: AVL树是一种高度平衡的二叉搜索树,其命名源自于联合发明算法的三位科学家的名字的首字母.此处“平衡”的定义是:任意节点的左右子树的高度相差不超过1.有了这个平衡的性质,使得AVL树的高度H总是接近log(N),因此各种增删改查的操作的复杂度能够保证在对数级别.没有bad case是AVL树与普通的二叉搜索树的最大区别.为了实现平衡性质,我们需要记录每个节点的高度(或者平衡因子)来检测不平衡的情况.为了修正高度不平衡,需要用到“旋转”的方法,分为单旋转和双

HDU HDOJ5412(树套树

题目:要求支持带修改维护区间第k大的值.所谓的动态区间第k大. 思路:题解说的是树状数组套treap,然而没想通树状数组怎么维护...线段树的话就是把所有的值离散化一下,离线建个关于值的线段树,每个节点是一个treap,treap里的值用位置做关键字,然后做区间查询,复杂度是O(nlogn*logn).基本也是经典的树套树做法....然后赛后写了两遍都没过.....今天心血来潮再挑战一下,结果从8点调到晚上1点.其间各种爆内存各种re各种t.....随机数据对拍了好久没拍出问题来....然后一直

HDU 4417 Super Mario ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )

HDU 4417 - Super Mario ( 主席树 + 线段树/树状数组离线处理 + 划分树 ) 这道题有很多种做法,我先学习的是主席树.后面陆续补上线段树离线和划分树 题目大意就是给定一个区间给定一个数列,每次要求你查询区间[L,R]内不超过K的数的数量 主席树做法: 最基本的是静态第k大,这里是求静态的 <= K,差不多,在Query操作里面需要修改修改 先建立size棵主席树,然后询问的时候统计的是 第R棵主席树中[1,K]的数量 - 第L-1棵主席树中[1,K]的数量 注意这里下标

树-伸展树(Splay Tree)

伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二叉查找树,即它具有和二叉查找树一样的性质:假设x为树中的任意一个结点,x节点包含关键字key,节点x的key值记为key[x].如果y是x的左子树中的一个结点,则key[y] <= key[x]:如果y是x的右子树的一个结点,则key[y] >= key[x]. (02) 除了拥有二叉查找树的性质

动态树之树链剖分

一些不需要link-cut操作的树上路径的题可以用树链剖分做,常数比lct小多了. 学习了下hld(树链剖分),嗯,挺简单的.hld可以在树中的操作有很多,hld可以说只是一种概念结构,它可以套很多其它的数据结构来进行操作,比如我现在只要求路径最值和求和,那么套线段树就行了:如果我要求第k大,可以套splay和主席树(这个不知道),也可以套分块(不会,分块以后学,必须学..)但是我觉得,树剖比lct还要难写..我lct一下就能写出来了..可是lct的常数,不忍直视..概念: 重儿子:num[u]

线段树或树状数组求逆序数(附例题)

学习了博主:MyZee   , shengweison 的文章 线段树或树状数组求逆序数 假设给你一个序列 6 1 2 7 3 4 8 5,  首先我们先手算逆序数, 设逆序数为 N; 6的前面没有比他大的数 N +=0 1的前面有一个比他大的数 N+=1 2的前面有一个比他大的数 N+=1 7的前面没有比他大的数 N+=0 ... 最后得到 N = 0 + 1 + 1 + 0 + 2 + 2 + 0 + 3 = 9 其实我们可用用线段树,或者树状数组模拟这个过程. 又因为线段树和树状数组的效率