定义:

一棵m阶B-树是拥有以下性质的多路查找树:

1、非叶子结点的根结点至少拥有两棵子树;

2、每一个非根且非叶子的结点含有k-1个关键字以及k个子树,其中⌈m/2⌉≤k≤m;

3、每一个叶子结点都具有k-1个关键字,其中⌈m/2⌉≤k≤m;

4、key[i]和key[i+1]之间的孩子节点的值介于key[i]、key[i+1]之间

5、所有的叶子结点都在同一层。

ps: ⌈m/2⌉是向上取整

建立B-树的节点:

template<class K,int M=3>
struct BTreeNode
{
K _key[M]; //关键字 (有效关键字个数为M-1)
BTreeNode<K, M>* _sub[M + 1]; //链接子树的指针数组
size_t _size; //节点中关键字的个数
BTreeNode<K, M>* _parent; //指向父节点的指针 BTreeNode()
:_size(0)
, _parent(NULL)
{
for (size_t i = 0; i < M + 1; i++)
{
_sub[i] = NULL;
}
}
};

插入数据key:

M阶B树--M=3:

用例 {53, 75, 139, 49, 145, 36, 101};

根据上面这些图,依次插入这些数据时的变化一目了然。现在就来看代码:

在插入一个数据前,我们首先要找到你要插入的位置,这里实现一个find函数寻找插入点,辅助插入数据key;

但是这里find函数的返回值该如何处理?bool或int都不行,这两个都不能满足我们的要求。BTreeNode类型也不太合适,找到key就返回该节点无可厚非;但是如果你查找的时候已经遍历到NULL了,说明没有找到数据key,这时候难道返回NULL吗?显然不合适,要插入的位置不能是NULL,这时候应该返回的是当前NULL的父亲结点,也就是我要插入数据的位置了。

那么找到就返回该节点以及该数据所在的关键字数组的下标,未找到就返回-1及父节点,这里我们可以将将它们封装起来,如下:

template<class K,class V>
struct Pair
{
K _first;
V _second; Pair(const K &k = K(), const V& v = V())
:_first(k)
, _second(v)
{}
};

返回值类型确定好的,其它的就好办了:

查找函数思想:

遍历关键字数组_key[],如果key比它小就 ++i 并继续往后遍历
1.如果key=_key[i]则停止遍历,返回该结构体节点
2.如果key比它大则停止遍历,此时的子树_sub[i]指向的关键字数组的所有数据都是介于_key[i-1]和_key[i]之间的数据,我们要找的key或许就在其中
3.如果跳出循环则未找到该数据cur=NULL,返回cur的父节点;这时候若是插入key,就插入到parent指向的关键字数组中

        //递归查找key
Pair<BTreeNode<K, M>*, int> Find(const K& key)
{
BTreeNode<K, M>* parent=NULL;
BTreeNode<K, M>* cur=_root; while (cur!=NULL)
{
size_t i = 0;
while (i < cur->_size&&cur->_key[i] < key)
++i;
if (cur->_key[i] == key)
return Pair<BTreeNode<K, M>*, int>(cur, i);
// key<_key[i] 则走向与key[i]下标相同的子树
parent = cur;
cur = cur->_sub[i];
}
return Pair<BTreeNode<K, M>*, int>(parent, -1);
}

找到位置后,就可以插入该数据key了

分情况:

1.B-树为NULL

2.B-树中已经存在key

3.B-树中不存在key,先把key以插入排序的方式插入到关键字数组中,判断该关键字数组是否已满,满了就要进行分裂。注意,这里的分裂有时可能不止一次!

//插入数据
bool Insert(K& key)
{
// 1.B-树为空
if (NULL == _root)
{
_root = new BTreeNode<K, M>;
_root->_key[0] = key;
++_root->_size;
return true;
} Pair<BTreeNode<K, M>*, int> ret = Find(key);
// 2.该数据已经存在
if (ret._second != -1)
return false; // 3.插入数据到关键字数组
BTreeNode<K, M>* cur = ret._first;
BTreeNode<K, M>* sub = NULL;
while (1)
{
int i = 0;
for ( i = cur->_size - 1; i >= 0; )
{ // 把大数往后挪,对应子树也要进行挪动
if (cur->_key[i] > key)
{
cur->_key[i + 1] = cur->_key[i];
cur->_sub[i + 2] = cur->_sub[i + 1];
i--;
}
else
{
break;
}
}
cur->_key[i + 1] = key;
cur->_sub[i + 2] = sub;
if (sub!=NULL)
cur->_sub[i+2]->_parent = cur;
cur->_size++; //关键字数组未满,插入成功
if (cur->_size < M)
return true; //关键字数组已满,需要进行分裂
int mid = M / 2;
BTreeNode<K, M>* tmp = new BTreeNode<K, M>;
int index = 0;
size_t k; for ( k = mid + 1; k < cur->_size; k++)
{
tmp->_key[index] = cur->_key[k];
if (cur->_sub[k] != NULL)
{
tmp->_sub[index] = cur->_sub[k];
cur->_sub[k] = NULL;
tmp->_sub[index]->_parent = tmp;
}
tmp->_size++;
cur->_size--;
index++;
}
if (cur->_sub[k] != NULL)
{
tmp->_sub[index] = cur->_sub[k];
cur->_sub[k] = NULL;
tmp->_sub[index]->_parent = tmp;
}
//父节点为空时的链接
if (cur->_parent == NULL)
{
_root = new BTreeNode<K, M>;
_root->_key[0] = cur->_key[mid];
cur->_size--;
_root->_sub[0] = cur;
_root->_sub[1] = tmp;
_root->_size++; //链接
tmp->_parent = _root;
cur->_parent = _root;
return true;
}
//父节点不为空时的链接
key = cur->_key[mid];
cur->_size--;
cur = cur->_parent;
sub = tmp;
}
}

  要看完整代码,可以去我的github查看代码:https://github.com/Lynn-zhang/BTree

B-树 C++模板类封装(有图有真相)的更多相关文章

  1. c++ char_traits模板类的实现!!!

    本人写过与此相关的两篇博客,一个是<cstring>头文件的实现,还有一个是<cwchar>的实现.这里的char_traits模板类在此基础上实现. 为了方便.将源码一起封装 ...

  2. 开涛spring3(7.2) - 对JDBC的支持 之 7.2 JDBC模板类

    7.2  JDBC模板类 7.2.1  概述 Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDB ...

  3. .Net Core ORM选择之路,哪个才适合你 通用查询类封装之Mongodb篇 Snowflake(雪花算法)的JavaScript实现 【开发记录】如何在B/S项目中使用中国天气的实时天气功能 【开发记录】微信小游戏开发入门——俄罗斯方块

    .Net Core ORM选择之路,哪个才适合你   因为老板的一句话公司项目需要迁移到.Net Core ,但是以前同事用的ORM不支持.Net Core 开发过程也遇到了各种坑,插入条数多了也特别 ...

  4. (转)JDBC模板类。

    Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDBC模板类是第一种工作模式. JdbcTempl ...

  5. spring3:对JDBC的支持 之 JDBC模板类

    7.2  JDBC模板类 7.2.1  概述 Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDB ...

  6. ASP.NET MVC深入浅出(被替换) 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式 第三节: EF调用普通SQL语句的两类封装(ExecuteSqlCommand和SqlQuery ) 第四节: EF调用存储过程的通用写法和DBFirst模式子类调用的特有写法 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性) 第十节: EF的三种追踪

    ASP.NET MVC深入浅出(被替换)   一. 谈情怀-ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态 ...

  7. Vector模板类----构造与析构

    /* 基于C++平台*/ typedef int rank; //用int来定义 “秩” 这种概念 #define DEFAULT_CAPACIITY 3 //默认初始容量,实际应用中可以取更大的值 ...

  8. C++基础 (9) 第九天 编译器对模板类的二次编译 类模板 自定义数组类

    1 昨日回顾 2 编译器对于模板的二次编译 写一个模板函数 然后进行调用 g++ template.cpp -o template // 汇编 g++ -S template.cpp –o templ ...

  9. Spring JDBC模板类—org.springframework.jdbc.core.JdbcTemplate(转)

    今天看了下Spring的源码——关于JDBC的"薄"封装,Spring 用一个Spring JDBC模板类来封装了繁琐的JDBC操作.下面仔细讲解一下Spring JDBC框架. ...

随机推荐

  1. 利用JNDI的命名与服务功能来满足企业级API对命名与服务的访问

    包含了大量的命名和目录服务,使用通用接口来访问不同种类的服务: 可以同时连接到多个命名或目录服务上: 建立起逻辑关联,允许把名称同Java对象或资源关联起来,而不必知道对象或资源的物理ID. JNDI ...

  2. Struts2 结果和结果类型

    正如前面提到的,<results>标签在Struts2的MVC框架的视图中所扮演的角色.动作是负责执行业务逻辑.执行业务逻辑后,接下来的步骤是使用<results>标签显示的视 ...

  3. openstack组件通讯端口定义

    openstack 组件通讯是通过ZeroMQ+ceilometer发送组件调用信息,具体是通过TCP通讯,发送数据和接收数据是用同一个端口(在配置文件指定),下面通过代码稍作解析: IceHouse ...

  4. Unity3D学习笔记——NGUI之UIButton

    前言:用于接受点击,悬停,触摸等事件.UIButton还有重要的用途,就是改变控件不同状态下的颜色. 一:使用方式: 1.在UI Root中右键创建一个Sprite 2.为其添加一个碰撞组件,就添加B ...

  5. SQL Server 阻止了对组件“Ad Hoc Distributed Queries”的 STATEMENT“OpenRowset/OpenDatasource”的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。系统管理员可以通过使用 sp_configure 启用“Ad Hoc Distributed Queries”。有关启用“Ad Hoc Distributed Queries”

    1.开启Ad Hoc Distributed Queries组件,在sql查询编辑器中执行如下语句: exec sp_configure reconfigure exec sp_configure r ...

  6. 使用RestTemplate发送multipart/form-data格式的数据

    现有业务场景需要使用RestTemplate发送一个post请求,请求格式为multipart/form-data的,可以使用以下方法: public Object sendRequest(Objec ...

  7. 【BZOJ1937】[Shoi2004]Mst 最小生成树 KM算法(线性规划)

    [BZOJ1937][Shoi2004]Mst 最小生成树 Description Input 第一行为N.M,其中 表示顶点的数目, 表示边的数目.顶点的编号为1.2.3.…….N-1.N.接下来的 ...

  8. 【BZOJ2298】[HAOI2011]problem a DP

    [BZOJ2298][HAOI2011]problem a Description 一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低.”问最少有几个人没有说真话(可能有相 ...

  9. 【BZOJ4810】[Ynoi2017]由乃的玉米田 bitset+莫队

    [BZOJ4810][Ynoi2017]由乃的玉米田 Description 由乃在自己的农田边散步,她突然发现田里的一排玉米非常的不美.这排玉米一共有N株,它们的高度参差不齐.由乃认为玉米田不美,所 ...

  10. POJ 2485 Highways【最小生成树最大权——简单模板】

    链接: http://poj.org/problem?id=2485 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22010#probl ...