c语言B树深入理解

 更新时间:2012年11月26日 11:02:43   投稿:whsnow  
B树是为磁盘或其他直接存储设备设计的一种平衡查找树,本文将详细介绍c语言B树,需要的朋友可以参考下

B树是为磁盘或其他直接存储设备设计的一种平衡查找树。如下图所示。每一个结点箭头指向的我们称为入度,指出去的称为出度。树结构的结点入度都是1,不然就变成图了,所以我们一般说树的度就是指树结点的出度,也就是一个结点的子结点个数。有了度的概念我们就简单定义一下B树(假设一棵树的最小度数为M):
1.每个结点至少有M-1个关键码,至多有2M-1个关键码;
2.除根结点和叶子结点外,每个结点至少有M个子结点,至多有2M个子结点;
3.根结点至少有2个子结点,唯一例外是只有根结点的情况,此时没有子结点;
4.所有叶子结点在同一层。

我们看看它的结点的结构,如下图所示:


每个结点存放着关键字和指向子结点的指针,很容易看出指针比关键码多一个。

由B树的定义我们可以看出它的一些特点:
1.树高平衡,所有叶结点在同一层;
2.关键字没有重复,按升序排序,父结点的关键码是子结点的分界;
3.B树把值接近的相关记录放在同一磁盘页中,从而利用了访问局部性原理;
4.B树保证一定比例的结点是满的,能改进空间利用率。

B树结点的大小怎么确定呢?为了最小化磁盘操作,通常把结点大小设为一个磁盘页的大小。一般树的高度不会超过3层,也就是说,查找一个关键码只需要3次磁盘操作就可以了。
在实现的时候,我是参照了《算法导论》的内容,先假定:
1.B树的根结点始终在主存中,不需要读磁盘操作;但是,根结点改变后要进行一次写磁盘操作;
2.任何结点被当做参数传递的时候,要读磁盘。

在实现的时候其实还做了简化,每个结点除了包含关键码和指针外,还应该有该关键码所对应记录所在文件的信息的,比如文件偏移量,要不然怎么找到这条记录呢。在实现的时候这个附加数据就没有放在结点里面了,下面是定义树的结构,文件名为btrees.h,内容如下:

复制代码 代码如下:

/* btrees.h */
# define M 2
/* B树的最小度数M>=2
* 每个非根结点必须至少有M-1个关键字。每个非根结点至少有M个子女
* 每个结点可包含至多2M-1个关键字。所以一个内结点至多可以有2M个子女
*/
typedef int bool ;
struct btnode{ /* B树结点 */
int keyNum; /* 节点中键的数目 */
int k[2*M-1]; /* 键 */
struct btnode * p[2*M]; /* 指向子树的指针 */
bool isleaf;
};
struct searchResult{
struct btnode *ptr; /* 数据所在节点指针 */
int pos; /* 数据在节点中位置 */
};

下面是创建一颗空树的代码,文件名为btree.c:
复制代码 代码如下:

# include <stdio.h>
# include <stdlib.h>
# include "btrees.h"
/* 给一个结点分配空间 */
struct btnode * allocateNode( struct btnode *ptr){
int i,max;
ptr = ( struct btnode *) malloc ( sizeof ( struct btnode));
if (!ptr){
printf ( "allocated error!/n" );
exit (1);
}
max = 2*M;
for (i=0; i<max; i++)
ptr->p[i] = NULL; /* 初始化指针 */
memset (ptr->k, 0, (max-1)* sizeof ( int )); /* 初始化键的值*/
return ptr;
}
/* 创建一个空的B树,就一个根结点 */
struct btnode * btreeCreate( struct btnode *root){
root = allocateNode(root);
root->keyNum = 0;
root->isleaf = 1;
return root;
}

他博客里面已经实现了,只是在定义B树的时候指针数和关键码数成一样了,我于是自己重写了一下。
[code]
void btreeSplitChild( struct btnode *parent, int pos, struct btnode *child){
struct btnode *child2;
int i;
child2 = allocateNode(child2);
child2->isleaf = child->isleaf;
//设置节点数
child2->keyNum = M-1;
//复制数据
for (i=0; i<M-1; i++)
child2->k[i] = child->k[i+M];
//如果不是叶节点,复制指针
if (!child->isleaf)
for (i=0; i<M; i++)
child2->p[i] = child->p[i+M];
child->keyNum = M-1;
for (i=parent->keyNum; i>pos; i--){
parent->k[i] = parent->k[i-1];
parent->p[i+1] = parent->p[i];
}
parent->k[pos] = child->k[M-1];
parent->keyNum++;
parent->p[pos+1] = child2;
}

相关文章

  • c++中的单例类模板的实现方法详解

    c++中的单例类模板的实现方法详解

    这篇文章主要介绍了c++中的单例类模板的实现方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • QT5.12连接MySQL的实现

    QT5.12连接MySQL的实现

    本文主要介绍了QT5.12连接MySQL的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-02-02
  • C++while和do-while语句求和详解

    C++while和do-while语句求和详解

    对于C语言中的while与do-while,相信很多都再熟悉不过了,最近在工作中就用到了,所以想着总结一下,方便自己或者有需要的朋友们参考借鉴,文中通过示例代码介绍的很详细,感兴趣的朋友们下面来一起学习学习吧
    2021-08-08
  • Qt http编程之nlohmann json库使用详解

    Qt http编程之nlohmann json库使用详解

    nlohmann是一个C++的JSON库,它提供了方便的方式来解析、生成和操作JSON数据,这篇文章主要为大家介绍了nlohmann json库的简单使用,希望对大家有所帮助
    2024-04-04
  • Matlab实现读写txt文件数据与进制转换

    Matlab实现读写txt文件数据与进制转换

    这篇文章主要为大家详细介绍了Matlab实现读写txt文件数据与进制转换的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • C语言实现常用字符串库函数(推荐)

    C语言实现常用字符串库函数(推荐)

    这篇文章主要介绍了C语言实现常用字符串库函数,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-11-11
  • C语言实现校运动会项目管理系统

    C语言实现校运动会项目管理系统

    这篇文章主要为大家详细介绍了C语言实现校运动会项目管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • C++的静态成员变量和静态成员函数你了解多少

    C++的静态成员变量和静态成员函数你了解多少

    这篇文章主要为大家详细介绍了C++的静态成员变量和静态成员函数,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • C++ 重载运算符在HotSpot VM中的应用小结

    C++ 重载运算符在HotSpot VM中的应用小结

    C++支持运算符重载,对于Java开发者来说,这个可能比较陌生一些,因为Java不支持运算符重载,下面介绍一下HotSpot VM中的运算符重载,感兴趣的朋友跟随小编一起看看吧
    2023-09-09
  • C++ lambda闭包消除类成员变量的解决思路

    C++ lambda闭包消除类成员变量的解决思路

    在面向对象编程中,类成员变量过多可能会造成干扰,可以采用函数式编程的思想,通过闭包和lambda表达式减少不必要的类成员,增强代码的可控性和减少干扰,注意要正确使用mutable修饰符和值捕获,以及合理安排lambda的初始化时机,感兴趣的朋友跟随小编一起看看吧
    2024-09-09

最新评论