当前位置:网站首页>B-树系列
B-树系列
2022-07-01 06:09:00 【qq_52025208】
B树
它是一种平衡的多叉树,称为B树。
一棵M阶(M>2)的B树,是一棵平衡的M路平衡搜索树。
B树的实现:
public class BTreeNode {
//一个B-树节点中,能存的key的数量的上限
public static final int KEY_LIMIT = 4;
//KEY_LIMIT+1:是因为插入空间已满不会进行分裂,再插入一个key使得>4的时候才会进行分裂
public long[] keyList = new long[KEY_LIMIT+1];
//记录目前拥有的key的个数
public int size = 0;
//区间范围
public BTreeNode[] childList = new BTreeNode[KEY_LIMIT+2];
public BTreeNode parent = null;
@Override
public String toString() {
return String.format("%d: %s", size, Arrays.toString(Arrays.copyOf(keyList, size)));
}
/** * 查找key位于哪一个子树中 */
public BTreeNode findKey(long key) {
if (key > keyList[size-1]) {
//最后一个数
return childList[size];
}
for (int i = 0; i < size; i++) {
if (key == keyList[i]) {
return this;
} else if (key < keyList[i]) {
//第一个大于key的关键字元素
return childList[i];
}
}
return null;
}
public InsertResult insertKeyWithChild(long key, BTreeNode node) {
// 1. 让 key 按序插入到 keyList 中
int index = insertIntoKeyList(key);
// 2. 根据 index 进行 child 的插入
// childList[0, size]
// [0, index] 不动
// [index + 1]位置 要插入 node 的下标
// [index + 1, size] 搬到 [index + 2, size + 1] 元素个数 == size - index
System.arraycopy(childList,index+1,childList,index+2,size-index);
childList[index+1] = node;
size++;
// 2. 判断是否需要进行分裂
// 3. 如果有必要,进行结点分裂
if (shouldSplit()) {
return splitNotLeaf();
}
return null;
}
//非叶子节点的分裂
private InsertResult splitNotLeaf() {
int size = this.size;
//1.找到中间位置
int index = size / 2;
//2.保存要分裂出的key
InsertResult result = new InsertResult();
result.key = keyList[index];
/** * 3. 处理 key 的分裂 * 哪些 key 应该留在当前结点中 [0,index) 一共index个 * 哪个 key 是分裂出的 key [index] * 哪些 key 应该在新结点中 (index,size) 一共size-index-1个 */
//将(index,size)位置上的key搬到新节点中
BTreeNode node = new BTreeNode();//创建新节点
System.arraycopy(keyList,index+1,node.keyList,0,size-index-1);
node.size = size-index-1;
//把 [index,size)所有的key重置为0,重置size
Arrays.fill(keyList,index,size,0);
this.size = index;
//4.对非叶子节点进行分裂
System.arraycopy(this.childList, index + 1, node.childList, 0, size - index);
//[index + 1, size + 1)
Arrays.fill(this.childList, index + 1, size + 1, null);
for (int i = 0; i < size - index; i++) {
node.childList[i].parent = node;
}
/** * 5.处理分裂的parent问题 * 1)this.parent不变,分裂不影响父子关系 * 2)node.parent和this是同一父亲 */
node.parent = this.parent;
result.node = node;
return result;
}
public static class InsertResult{
public long key; //分裂出的key
public BTreeNode node;//分裂出的新节点
}
public InsertResult insertKey(long key) {
//key 按序插入到 keyList 中
insertIntoKeyList(key);
size++;
//判断是否要进行分裂
if (shouldSplit( )) {
return splitLeaf();
}
return null;
}
//节点分裂
private InsertResult splitLeaf() {
int size = this.size;
//1.找到中间位置
int index = size / 2;
//2.保存要分裂出的key
InsertResult result = new InsertResult();
result.key = keyList[index];
/** * 3. 处理 key 的分裂 * 哪些 key 应该留在当前结点中 [0,index) 一共index个 * 哪个 key 是分裂出的 key [index] * 哪些 key 应该在新结点中 (index,size) 一共size-index-1个 */
//将(index,size)位置上的key搬到新节点中
BTreeNode node = new BTreeNode();//创建新节点
System.arraycopy(keyList,index+1,node.keyList,0,size-index-1);
node.size = size-index-1;
//把 [index,size)所有的key重置为0,重置size
Arrays.fill(keyList,index,size,0);
this.size = index;
//4.对叶子节点进行分裂,如果childList == null,则不需要分裂
/** * 5.处理分裂的parent问题 * 1)this.parent不变,分裂不影响父子关系 * 2)node.parent和this是同一父亲 */
node.parent = this.parent;
result.node = node;
return result;
}
//判断是否要进行分裂
private boolean shouldSplit() {
return size > KEY_LIMIT;
}
//key 按序插入到 keyList 中
private int insertIntoKeyList(long key) {
int i;
for (i = size-1; i >= 0; i--) {
if (keyList[i] < key) {
break;
}
//将值往后移动一格,继续查找
keyList[i+1] = keyList[i];
}
keyList[i+1] = key;
return i+1;
}
}
public class BTree {
//B-树的根节点
public BTreeNode root = null;
//B-树中key的个数
public int size = 0;
public boolean insert(long key) {
if (insertWithoutSize(key)) {
size++;
return true;
}
return false;
}
private boolean insertWithoutSize(long key) {
//判定是否是空树
if(root == null) {
root = new BTreeNode();
root.keyList[0] = key;
root.size = 1;
return true;
}
//不是空树
BTreeNode cur = root;
while (true) {
BTreeNode node = cur.findKey(key);
if (node == cur) {
//key就在cur节点中
//不能重复插入
return false;
} else if (node == null) {
//cur就是叶子节点,直接插入
break;
} else {
//找到一个孩子,而且cur不是叶子
cur = node;
}
}
//进行key的插入
BTreeNode.InsertResult result = cur.insertKey(key);
while (true) {
if (result == null) {
//插入中没有发生节点分裂
return true;
}
//说明发生了分裂
//需要把分裂出key和新节点插入相应的节点
BTreeNode parent = cur.parent;
if (parent == null) {
//cur是根节点
//根结点发生分裂了
// 需要一个新的根结点,来保存分裂出的 key
root = new BTreeNode();
root.keyList[0] = result.key;
root.size = 1;
root.childList[0] = cur;
root.childList[1] = result.node;
// 由于原来 current 是根结点,所以其 parent == null
// 自然分裂出的结点,跟着也是 null
// 所以为他们设置新的父结点
cur.parent = result.node.parent = root;
return true;
}
//不是根节点插入
result = parent.insertKeyWithChild(result.key,result.node);
cur = parent;
}
}
}
B+树
B+树的搜索与B-树基本相同,区别是B+树只有达到叶子节点才能命中(B-树可以在非叶子节点中命中)。
key一定都在叶子中保存一份。叶子节点通过链式结构关联。
数据库中常需要全key的扫描。
B+树的特性:
(1)所有关键字都出现在叶子节点的链表中(稠密索引),且链表中的节点都是有序的。
(2)不可能在非叶子节点中命中。
(3) 非叶子节点相当于是叶子节点的索引(稀疏索引),叶子节点相当于是存储数据的数据层。
(4)更适合文件索引系统
B+树与B-树的区别:
B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子节点存储指向关键字范围的节点;所有关键字在整棵树中出现,且只出现了一次,非叶子节点可以命中;
B+树:在B-树的基础上,为叶子节点增加链表指针,所有关键字都在叶子节点中出现,非叶子节点作为叶子节点的索引;B+树总是到叶子节点才可以命中。
边栏推荐
- [note] e-commerce order data analysis practice
- Thoughts on a "01 knapsack problem" expansion problem
- Factorial divisor (unique decomposition theorem)
- Distributed lock implementation
- Multi label lsml for essay learning records
- Record currency in MySQL
- SystemVerilog学习-10-验证量化和覆盖率
- Some errors encountered in MySQL data migration
- SystemVerilog学习-07-类的继承和包的使用
- Scope data export mat
猜你喜欢

机械臂速成小指南(六):步进电机驱动器

【文件系统】如何在ubi之上运行squashfs

Freeswitch dial the extension number

Tidb database characteristics summary

What if the data in the cloud disk is harmonious?

Transformer le village de tiantou en un village de betteraves sucrières

68 Cesium代码datasource加载czml

Ant new village is one of the special agricultural products that make Tiantou village in Guankou Town, Xiamen become Tiantou village

无限水平大理石游戏

three.js小结
随机推荐
端口扫描工具是什么?端口扫描工具有什么用
jdbc 数据库操作
golang panic recover自定义异常处理
Diagramme dynamique Excel
地宮取寶(記憶化深搜)
Factorial divisor (unique decomposition theorem)
Geoffrey Hinton: my 50 years of in-depth study and Research on mental skills
Multi label lsml for essay learning records
【ManageEngine卓豪】移动终端管理解决方案,助力中州航空产业数字化转型
Code shoe set - mt3114 · interesting balance - explain it with examples
基于LabVIEW的计时器
DEV XPO对比之XAF BO
PLA not pasted on the bed: 6 simple solutions
SystemVerilog学习-08-随机约束和线程控制
Tidb database characteristics summary
pycharm 配置jupyter
uniapp树形层级选择器
Transformer le village de tiantou en un village de betteraves sucrières
分布式锁实现
3D printer threading: five simple solutions