一:简介
B树是为磁盘而设计的一种平衡查找树,类似于红黑树,但在降低磁盘io次数上更好一些!常用于数据库系统。B树不同于红黑树主要在于B树的结点可以有许多子女,这是由磁盘的特性决定的。因此,B树可以在O(lgN)的时间内完成许多动态几何的操作!
二:性质
如果B树的内结点x含有N[x]个关键字,则x就含有N[x]+1个子女。结点X用来将x的关键字域划分成n[x]+1个域。在查找某个关键字时,就可以通过对X中的x[n]个关键字的比较,来得出n[x]+1路的决定!
因为是对磁盘而设计的数据结构,故对磁盘的读取次数是对数据结构的衡量标准之一!一个B树的分支因子越大,则同样的关键字时,B树的高度就越小,对磁盘的读取次数也就越小!
三:B树的定义
一颗B树是具有如下性质的有根树:
1. 每个节点有三个域:n[x]:节点x中的关键字数;n[x]个关键字本身,并且按非减次序排序;布尔量leaf[x] 指示x是否是叶节点。
2. 每个内结点有n[x]+1个指向其子女的指针:c1[x],c2[x]…Cn[x]+1[x]。其中,叶节点的c域为空。
3. 各个关键字keyi[x]对存储在各子树中的关键字范围加以分割!假设ki为存储在以keyi[x]为根节点的子树中的关键字,则有:
K1<KEY1[x]<K2<KEY2[x]<K3<KEY3[x]……KEY n[x][X]<K n[x]+1
4. 每个叶节点有相同的高度,即树的高度为H
5. 每个节点包含的关键字树有一个上界和一个下界,这些界用一个称作B树的最小度数的固定整数t来表示!
6. 一个非根的结点至少有t-1个关键字,有t个子节点,如果一个树是非空树,则该树的根节点至少有一个关键字!
7. 每个结点可以至多包含2t-1个关键字和2t个子女,如果一个结点包含2t-1个关键字,则该节点称为满结点!
四:B树的高度
B树上的大多数操作所需的磁盘存取次数与B树的高度成正比的!
可以得到证明得到高度H和关键字树N和最小度数t的关系如下:
H<logt(N+1)/2
五:B树的基本操作之搜索
在每个内结点x处要做N[x]+1次的分支决定,而对于二叉树则只需2次分支决定,
他是对二叉树查找的一次推广!
伪代码如下:
B—TREE-SEARCH(x,k)
i=1
while i<n[x] and k>keyi[x]
do i=i+1
if i<n[x] and k==keyi[x]
then return(x,i)
if leaf[x]
then return null
else DISK-READ(ci[x])
return B-TREE- SEARCH(ci[x],k)
时间分析:B—TREE-SEARCH(x,k)所需的磁盘读取次数为:O(h)
由于n[x]<2t,故第三行的循环的时间为O(t) ,故总的才cpu时间为O(t*LOG t N)
六:B树的基本操作之插入
步骤是先调用B—TREE-CREATE(T)来创建一个空的根节点,再调用B—TREE-INSERT()来加入新的关键字,另外,还有一个辅助过程ALLOCATE-NODE他在O(1)的时间内创建一个新的结点!
1、创建一个新节点,这个比较简单伪代码如下:
B—TREE-CREATE(T)
x=ALLOCATE-NODE()
leaf[x]=true
n[x]=0
DISK-WRITE(x)
root[T]=x
2、对已经创建的空的根结点进行插入处理,这个比较复杂一些,因为创建了一个结点并不能简单的插入,而要保持B树的7大性质!此处,先用B—TREE-SPITE-CHILD来确保要插入处的结点以及该节点的双亲结点不是满结点。
A:B树中结点的分裂:伪代码如下
B—TREE-SPITE-CHILD(x,i,y) //其中Ci[x]=y
z= ALLOCATE-NODE()
leaf[z]=leaf[y]
n[z]=t-1
for j=1 to j=t-1
do key j[z]=key j+t[y]
if not leaf[y]
then for j=1 to t
do Cj[z]=Cj+t[y]
n[y]=t-1
for j=n[x]+1 down to i+1
do Cj+1[x]=Cj[x]
Ci+1=z
For j=n[x] down to i
do key(j+1)[x]=key(j)[x]
key(i)[x]=key(t)[y]
n[x]=n[x]+1
DISK-WRITE(y)
DISK-WRITE(z)
DISK-WRITE(x)
从以上的伪代码可以看出,B—TREE-SPITE-CHILD(x,i,y)是以“剪贴”的方式进行操作的,其中y是x的第i个孩子,也是要被分裂的结点!
B:对B树用单程下行的遍历方式插入关键字
在一颗高度为h的B树T中,插入一个关键字k的操作,是在延树下降的过程中一次完成的,共需要O(h)次的磁盘读取时间,并且此过程通过B—TREE-SPITE-CHILD保证递归始终不会降到一个满结点上。伪代码如下:
B—TREE-INSERT(T,k)
r=root[T]
if n[r]=2t-1
then s= ALLOCATE-NODE()
root[T]=s
leaf[s]=false
n[s]=0
C1[s]=r
B—TREE-SPITE-CHILD(s,1,r)
B—TREE-INSERT-NONFULL(s,k)
else B—TREE-INSERT-NONFULL(r,k)
C:调用B—TREE-INSERT-NONFULL将关键字k插入到非满的根节点中,此过程中适当的加入B—TREE-SPITE-CHILD操作,来确保每个结点都是非满的!直到结束为止,伪代码如下:
B—TREE-INSERT-NONFULL(x,k)
i=n[x]
if leaf[x]
then while i>1 and k<key(i) [x]
do key(i+1)[x]=key(i)[x]
i=i-1
key(i+1)=k
n[x]=n[x]+1
DISK-WRITE(x)
Else while i>1 and k<key(i)[x]
do i=i-1
i=i+1
DISK-READ(C(i)[x])
if n[C(i)[x]]=2t-1
then B—TREE-SPITE-CHILD(x,I,C(i)[x])
if k>key(i)[x]
then i=i+1
B—TREE-INSERT-NONFULL(C(i)[x],k)
时间分析:B—TREE-INSERT要做的磁盘存取次数为O(h),总的cpu时间O(t h)=O(t*LOGt N)!
七:B树的基本操作之删除
对B树的删除是B树操作中最为复杂的事情了,因为不止是从叶子结点中删除,而且会从内结点中删除,这样就要重新布置B树的结构,使其继续满足B树性质!
删除的操作比较复杂,故不再给出伪代码,主要分为如下几个大类:
<1>如果关键字k在结点x中,并且x是叶节点,则直接从x中删除k
<2>如果关键字所在的结点是内结点,则做如下操作:
A. 如果结点x中前于k的子节点y中至少包含t个关键字,即找出k在以y为根的子树中的前驱k’,递归的删除k’,并在x中用k’代替k。
B. 对称的,如果结点x中位于k之后的子节点z中至少包含t个关键字,即找出k在以z为根的子树中的后继k’,递归的删除k’,并在x中用k’代替k
C. 否则,如果y和z都只有t-1个关键字,则将k和z中的所有关键字合并到y中,使得x失去k和指向z的指针,然后释放z并在y中删除k。
<3>如果关键字k不在内结点x中,则确定必包含k的正确的子树的根C(i)[x],如果C(i)[x]只有t-1个关键字,执行以下的A或B来保证我们降至一个包含至少t个关键字的结点,然后,通过对x的某个子节点递归而结束。
A. 如果C(i)[x]只包含t-1个关键字,但他的一个相邻兄弟包含至少t个关键字,则将x中的某一个关键字降至C(i)[x]中,将C(i)[x]的相邻兄弟或者右兄弟中的某一关键字升至x中,并将该兄弟中合适的子女指针指向C(i)[x]中。
B. 如果C(i)[x]和她的所有兄弟都只包含t-1个关键字,则将C(i)[x]和任意一个兄弟结点合并,并在x结点中找出一个合适的关键字移植到新合并的结点中当做中间关键字。
删除操作的时间分析:
磁盘存取次数为O(h),总的cpu时间O(t h)=O(t*LOGt N)!
——记录于2013/3/17
B树是为磁盘而设计的一种平衡查找树,类似于红黑树,但在降低磁盘io次数上更好一些!常用于数据库系统。B树不同于红黑树主要在于B树的结点可以有许多子女,这是由磁盘的特性决定的。因此,B树可以在O(lgN)的时间内完成许多动态几何的操作!
二:性质
如果B树的内结点x含有N[x]个关键字,则x就含有N[x]+1个子女。结点X用来将x的关键字域划分成n[x]+1个域。在查找某个关键字时,就可以通过对X中的x[n]个关键字的比较,来得出n[x]+1路的决定!
因为是对磁盘而设计的数据结构,故对磁盘的读取次数是对数据结构的衡量标准之一!一个B树的分支因子越大,则同样的关键字时,B树的高度就越小,对磁盘的读取次数也就越小!
三:B树的定义
一颗B树是具有如下性质的有根树:
1. 每个节点有三个域:n[x]:节点x中的关键字数;n[x]个关键字本身,并且按非减次序排序;布尔量leaf[x] 指示x是否是叶节点。
2. 每个内结点有n[x]+1个指向其子女的指针:c1[x],c2[x]…Cn[x]+1[x]。其中,叶节点的c域为空。
3. 各个关键字keyi[x]对存储在各子树中的关键字范围加以分割!假设ki为存储在以keyi[x]为根节点的子树中的关键字,则有:
K1<KEY1[x]<K2<KEY2[x]<K3<KEY3[x]……KEY n[x][X]<K n[x]+1
4. 每个叶节点有相同的高度,即树的高度为H
5. 每个节点包含的关键字树有一个上界和一个下界,这些界用一个称作B树的最小度数的固定整数t来表示!
6. 一个非根的结点至少有t-1个关键字,有t个子节点,如果一个树是非空树,则该树的根节点至少有一个关键字!
7. 每个结点可以至多包含2t-1个关键字和2t个子女,如果一个结点包含2t-1个关键字,则该节点称为满结点!
四:B树的高度
B树上的大多数操作所需的磁盘存取次数与B树的高度成正比的!
可以得到证明得到高度H和关键字树N和最小度数t的关系如下:
H<logt(N+1)/2
五:B树的基本操作之搜索
在每个内结点x处要做N[x]+1次的分支决定,而对于二叉树则只需2次分支决定,
他是对二叉树查找的一次推广!
伪代码如下:
B—TREE-SEARCH(x,k)
i=1
while i<n[x] and k>keyi[x]
do i=i+1
if i<n[x] and k==keyi[x]
then return(x,i)
if leaf[x]
then return null
else DISK-READ(ci[x])
return B-TREE- SEARCH(ci[x],k)
时间分析:B—TREE-SEARCH(x,k)所需的磁盘读取次数为:O(h)
由于n[x]<2t,故第三行的循环的时间为O(t) ,故总的才cpu时间为O(t*LOG t N)
六:B树的基本操作之插入
步骤是先调用B—TREE-CREATE(T)来创建一个空的根节点,再调用B—TREE-INSERT()来加入新的关键字,另外,还有一个辅助过程ALLOCATE-NODE他在O(1)的时间内创建一个新的结点!
1、创建一个新节点,这个比较简单伪代码如下:
B—TREE-CREATE(T)
x=ALLOCATE-NODE()
leaf[x]=true
n[x]=0
DISK-WRITE(x)
root[T]=x
2、对已经创建的空的根结点进行插入处理,这个比较复杂一些,因为创建了一个结点并不能简单的插入,而要保持B树的7大性质!此处,先用B—TREE-SPITE-CHILD来确保要插入处的结点以及该节点的双亲结点不是满结点。
A:B树中结点的分裂:伪代码如下
B—TREE-SPITE-CHILD(x,i,y) //其中Ci[x]=y
z= ALLOCATE-NODE()
leaf[z]=leaf[y]
n[z]=t-1
for j=1 to j=t-1
do key j[z]=key j+t[y]
if not leaf[y]
then for j=1 to t
do Cj[z]=Cj+t[y]
n[y]=t-1
for j=n[x]+1 down to i+1
do Cj+1[x]=Cj[x]
Ci+1=z
For j=n[x] down to i
do key(j+1)[x]=key(j)[x]
key(i)[x]=key(t)[y]
n[x]=n[x]+1
DISK-WRITE(y)
DISK-WRITE(z)
DISK-WRITE(x)
从以上的伪代码可以看出,B—TREE-SPITE-CHILD(x,i,y)是以“剪贴”的方式进行操作的,其中y是x的第i个孩子,也是要被分裂的结点!
B:对B树用单程下行的遍历方式插入关键字
在一颗高度为h的B树T中,插入一个关键字k的操作,是在延树下降的过程中一次完成的,共需要O(h)次的磁盘读取时间,并且此过程通过B—TREE-SPITE-CHILD保证递归始终不会降到一个满结点上。伪代码如下:
B—TREE-INSERT(T,k)
r=root[T]
if n[r]=2t-1
then s= ALLOCATE-NODE()
root[T]=s
leaf[s]=false
n[s]=0
C1[s]=r
B—TREE-SPITE-CHILD(s,1,r)
B—TREE-INSERT-NONFULL(s,k)
else B—TREE-INSERT-NONFULL(r,k)
C:调用B—TREE-INSERT-NONFULL将关键字k插入到非满的根节点中,此过程中适当的加入B—TREE-SPITE-CHILD操作,来确保每个结点都是非满的!直到结束为止,伪代码如下:
B—TREE-INSERT-NONFULL(x,k)
i=n[x]
if leaf[x]
then while i>1 and k<key(i) [x]
do key(i+1)[x]=key(i)[x]
i=i-1
key(i+1)=k
n[x]=n[x]+1
DISK-WRITE(x)
Else while i>1 and k<key(i)[x]
do i=i-1
i=i+1
DISK-READ(C(i)[x])
if n[C(i)[x]]=2t-1
then B—TREE-SPITE-CHILD(x,I,C(i)[x])
if k>key(i)[x]
then i=i+1
B—TREE-INSERT-NONFULL(C(i)[x],k)
时间分析:B—TREE-INSERT要做的磁盘存取次数为O(h),总的cpu时间O(t h)=O(t*LOGt N)!
七:B树的基本操作之删除
对B树的删除是B树操作中最为复杂的事情了,因为不止是从叶子结点中删除,而且会从内结点中删除,这样就要重新布置B树的结构,使其继续满足B树性质!
删除的操作比较复杂,故不再给出伪代码,主要分为如下几个大类:
<1>如果关键字k在结点x中,并且x是叶节点,则直接从x中删除k
<2>如果关键字所在的结点是内结点,则做如下操作:
A. 如果结点x中前于k的子节点y中至少包含t个关键字,即找出k在以y为根的子树中的前驱k’,递归的删除k’,并在x中用k’代替k。
B. 对称的,如果结点x中位于k之后的子节点z中至少包含t个关键字,即找出k在以z为根的子树中的后继k’,递归的删除k’,并在x中用k’代替k
C. 否则,如果y和z都只有t-1个关键字,则将k和z中的所有关键字合并到y中,使得x失去k和指向z的指针,然后释放z并在y中删除k。
<3>如果关键字k不在内结点x中,则确定必包含k的正确的子树的根C(i)[x],如果C(i)[x]只有t-1个关键字,执行以下的A或B来保证我们降至一个包含至少t个关键字的结点,然后,通过对x的某个子节点递归而结束。
A. 如果C(i)[x]只包含t-1个关键字,但他的一个相邻兄弟包含至少t个关键字,则将x中的某一个关键字降至C(i)[x]中,将C(i)[x]的相邻兄弟或者右兄弟中的某一关键字升至x中,并将该兄弟中合适的子女指针指向C(i)[x]中。
B. 如果C(i)[x]和她的所有兄弟都只包含t-1个关键字,则将C(i)[x]和任意一个兄弟结点合并,并在x结点中找出一个合适的关键字移植到新合并的结点中当做中间关键字。
删除操作的时间分析:
磁盘存取次数为O(h),总的cpu时间O(t h)=O(t*LOGt N)!
——记录于2013/3/17
318

被折叠的 条评论
为什么被折叠?



