我们谈起B+树,可能最先想到它是MySQL中底层存储所采用的数据结构,其实B+树和二叉树、平衡二叉树一样,都是经典的数据结构。B+树由B树和索引顺序访问方法(ISAM,是不是很熟悉?对,这也是MyISAM引擎最初参考的数据结构)演化而来,MongDB中就采用的B树。
为啥MySQL中不采用B树,而采用B+树呢?(或者说MongDB中为啥不采用B+树呢?)
这是因为MySql是关系型数据库,数据的关联性是非常强的,区间访问是常见的一种情况,底层索引组织数据使用B+树,B+树由于数据全部存储在叶子节点,并且通过指针串在一起,这样就很容易的进行区间遍历甚至全部遍历。MongoDB使用B树,所有节点都有Data域,只要找到指索引就可以进行访问,单次查询从结构上来看要快于MySql。
B+树是数据库所需而出现的一种B树的变形树。(这里借用王道书中,对B+树的定义)
一棵m阶的B+树需满足下列条件:
1)每个分支节点最多有m棵子树(子节点)。
2)非叶根节点至少有两棵子树,其他每个分支节点至少有⌈m/2⌉棵子树。
3)节点的子树与关键字个数相等。
4)所有叶节点包含全部关键字及指向相应记录的指针,而且叶节点中将关键字按大小顺序排列,并且相邻叶节点按大小顺序相互链接起来,m阶的B+树最多有m个关键字。
5)所有分支节点(可看成索引的索引)中仅包含他的各个子节点(即下一级的索引块)中关键字的最大值及指向其子节点的指针。
m阶的B+树与B树的主要差异在于:
isLeaf:起初想为叶子节点和非叶子节点设计两个数据结构,然后发现两个数据结构不如一个数据结构方便管理,所以选择一个结构,既能表示叶子节点,又能表示非叶子节点。(boolean)
parent:node的父节点,每次需要分裂节点,需要找到分裂节点的父节点,将新生成的节点作为父节点的子节点。(Node
nodeIndex:表示该节点node在父节点的索引值,这是因为当父节点的节点个数非常多的时候,直接根据索引找到node在父节点中的位置,如果没有nodeIndex,顺序查找未免太费时间了,这里属于是空间换时间了。(int)
degree:度,也是阶数,表示该节点能存储几个元素entry。(int)
entries:存储元素entry的列表;V是你传进来的类型,K是根据V生成的hash值,由KV共同构成Entry。(List
nodeList:如果是叶子节点,则存储左节点和右节点;如果是非叶子节点,则存储子节点。(List
如下所示:
degree:初始化B+树时,需要完成node的degree的赋值操作,表示degree阶B+树。
head:头节点,指向B+树的最高层的节点,增删查都需要用到head,head指向的节点的nodeIndex为-1。
half:等于(degree + 1) / 2;很多时候都会用到这个,例如节点分裂,节点合并时的可借和不可借,详情见后面代码。
初始化之后会生成一个叶节点,head指向叶节点
当该节点的 entries的元素个数 <= degree 则能直接插入,插入之后,有两种情况:
当该节点的 entries的元素个数 > half 则能直接删除,删除之后,有两种情况:
package com.thinking.tree;
public class Entry<K, V> {
private K key;
private V value;
public void setKey(K key) {
this.key = key;
}
public K getKey() {
return this.key;
}
public void setValue(V value) {
this.value = value;
}
public V getValue() {
return this.value;
}
public Entry(K key, V value) {
this.key = key;
this.value = value;
}
public Entry() {
}
@Override
public String toString() {
return "key: " + this.key;
}
}
package com.thinking.tree;
import java.util.Comparator;
import java.util.List;
public class Node<K, V> {
private boolean isLeaf = true;
private Node<K, V> parent;
//该节点在其父节点中处于的索引处
private int nodeIndex;
private int degree;
private List<Entry<K, V>> entries;
private List<Node<K, V>> nodeList;
//键值比较函数对象,如果采用倒序或者其它排序方式,传入该对象
private Comparator<K> kComparator;
//比较两个key,如果没有传入自定义排序方式则采用默认的升序
public int compare(K key1, K key2) {
return this.kComparator == null ? ((Comparable<K>) key1).compareTo(key2) : kComparator.compare(key1, key2);
}
/**
* 在node中二分查找key值,无论存不存在,都要返回一个index
* @param key
* @return
* key存在,返回对应的index
* key不存在,返回大于key的最小值的索引
* 若没有大于key的值,则返回最大索引值
* 如下数组:
* ---------------------------------------------
* | 0 | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 |
* ---------------------------------------------
* 查找-1:返回index=0
* 查找 0:返回index=0
* 查找 1:返回index=1
* 查找40:返回index=4
* 查找71:返回index=8
* 查找80:返回index=8
* 查找81:返回index=8
*
*
* 查找-1:返回index=0
* 查找1 :返回index=1
* 查找11:返回index=2
* 查找21:返回index=3
* 查找31:返回index=4
* 查找41:返回index=5
* 查找51:返回index=6
* 查找61:返回index=7
* 查找71:返回index=8
* 查找81:返回index=8
*/
public SearchResult search(K key) {
int left = 0; //左指针
int right = this.getEntries().size() - 1;//右指针
int mid = (left + right) / 2;//中间的位置
boolean isExist = false; //判断是否找到了
int searchIndex = 0; //要找的关键字的下标
int maxIndex = right;//最大索引值
while(left <= right){
mid = (left + right)/2;//中间的位置
Entry<K,V> midEntry = this.entries.get(mid);//拿到中间的关键字
int comparator = this.compare(key, midEntry.getKey());
if(comparator == 0){//找到了
isExist = true;
searchIndex = mid;
break;
}else if(comparator==1){//在右侧
left = mid + 1;
}else{//midKey大于key 在左侧
right = mid - 1;
}
}
//二分查找结束了
//B树首次插入节点,会出现left = 0且right = -1的情况
if(isExist == false) {
if (right == -1) {
searchIndex = left;
} else {
//能走到这里说明left > right
//选择较大的哪个值,但是left可能会出现大于最大索引值的情况,这时取最大值
if (left <= maxIndex) {
searchIndex = left;
} else {
searchIndex = maxIndex;
}
}
}
List<Entry<K, V>> entries = this.getEntries();
/**要插入的key并不存在,但是我们参考如下
* ---------------------------------------------
* | 0 | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 |
* ---------------------------------------------
* 查找-1:返回index=0
* 查找 0:返回index=0
* 查找 1:返回index=1
* 查找40:返回index=4
* 查找71:返回index=8
* 查找80:返回index=8
* 查找81:返回index=8
*
* 我们插入71返回index=8,没问题
* 我们插入81也返回index=8,就有问题了,应返回index=9
* 所以这里需要判别一下
* 如果maxIndex == -1,说明叶子节点中还没有元素,则insertIndex为0
* 如果maxIndex >= 0
* 则需要判别key和maxKey的关系
* 如果key <= maxKey, insertIndex = searchIndex
* 如果key > maxKey, insertIndex = searchIndex + 1
*/
int insertIndex = -1;
if (maxIndex == -1) {
insertIndex = 0;
} else {
if (this.compare(key, entries.get(maxIndex).getKey()) == 1) {
insertIndex = searchIndex + 1;
} else {
insertIndex = searchIndex;
}
}
return new SearchResult(
isExist,
searchIndex,
insertIndex
);
}
public Node(int degree) {
this.degree = degree;
}
public boolean isLeaf() {
return isLeaf;
}
public void setLeaf(boolean leaf) {
isLeaf = leaf;
}
public List<Entry<K, V>> getEntries() {
return entries;
}
public void setEntries(List<Entry<K, V>> entries) {
this.entries = entries;
}
public List<Node<K, V>> getNodeList() {
return nodeList;
}
public void setNodeList(List<Node<K, V>> nodeList) {
this.nodeList = nodeList;
}
public Node<K, V> getParent() {
return parent;
}
public void setParent(Node<K, V> parent) {
this.parent = parent;
}
public int getNodeIndex() {
return nodeIndex;
}
public void setNodeIndex(int nodeIndex) {
this.nodeIndex = nodeIndex;
}
public int getDegree() {
return degree;
}
public Node<K, V> getLeftNode() {
return isLeaf() == true ? nodeList.get(0) : null;
}
public Node<K, V> getRightNode() {
return isLeaf() == true ? nodeList.get(1) : null;
}
public void setLeftNode(Node<K, V> leftNode) {
if (isLeaf()) {
this.getNodeList().set(0, leftNode);
}
}
public void setRightNode(Node<K, V> rightNode) {
if (isLeaf()) {
this.getNodeList().set(1, rightNode);
}
}
}
package com.thinking.tree;
public class SearchResult<K, V> {
private boolean exist;
private int searchIndex;
private int insertIndex;
public SearchResult(boolean exist, int searchIndex, int insertIndex) {
this.exist = exist;
this.searchIndex = searchIndex;
this.insertIndex = insertIndex;
}
public boolean isExist() {
return exist;
}
public void setExist(boolean exist) {
this.exist = exist;
}
public int getSearchIndex() {
return searchIndex;
}
public void setSearchIndex(int searchIndex) {
this.searchIndex = searchIndex;
}
public int getInsertIndex() {
return insertIndex;
}
public void setInsertIndex(int insertIndex) {
this.insertIndex = insertIndex;
}
}
package com.thinking.tree;
import javafx.util.Pair;
import java.util.*;
public class BPlusTree<V> {
//默认是5阶树,度为5,当entries.size() = 6 时分裂
private static int DEFAULT_DEGREE = 5;
private int degree;
private Node<Integer, V> head= null;
private int half;
public BPlusTree() {
this(DEFAULT_DEGREE);
this.degree = DEFAULT_DEGREE;
}
/**
* 初始化时,完成head的指向,保证head随时都指向非叶子节点,减少head指向节点的判别
* @param degree
* degree为奇数的时候,this.degree = degree
* degree为偶数的时候,this.degree = degree + 1
* 实际使用的时候,degree会比较大,考虑奇偶意义不大,且会增加代码量,不易理解分裂和合并,所以这里只考虑一种情况,为偶数的情况
*/
public BPlusTree(int degree) {
head = newLeafNode();
this.degree = degree % 2 == 0 ? degree + 1 : degree;
this.half = (this.degree + 1)/2;
}
private Node<Integer, V> newLeafNode() {
Node<Integer, V> node = new Node<>(this.degree);
node.setLeaf(true);
ArrayList<Entry<Integer, V>> entries = new ArrayList<>(this.degree + 1);
node.setEntries(entries);
ArrayList<Node<Integer, V>> nodeList = new ArrayList<>(2);
nodeList.addAll(Arrays.asList(null, null));
node.setNodeList(nodeList);
node.setParent(null);
node.setNodeIndex(-1);
return node;
}
private Node<Integer, V> newBranchNode() {
Node<Integer, V> node = new Node<>(this.degree);
node.setLeaf(false);
ArrayList<Entry<Integer, V>> entries = new ArrayList<>(this.degree + 1);
ArrayList<Node<Integer, V>> nodeList = new ArrayList<>(this.degree + 1);
node.setEntries(entries);
node.setNodeList(nodeList);
node.setParent(null);
node.setNodeIndex(-1);
return node;
}
private Entry<Integer, V> newEntry(Integer key, V val) {
return new Entry<Integer, V>(key, val);
}
/**
* 添加元素
* @param val 插入元素
*/
public void insert(V val) {
//可根据val的hashCode生成key,但是为了测试方便且类比Mysql的主键
// 在mysql中,如果随机插入,在mysql中会频繁分页,使得插入性能降低,当然我们这里并不会考虑这些,类比学习还是可以的
// 故采用Integer类型的key
int key = val.hashCode();
insert(key, val);
}
public void delete(V val) {
int key = val.hashCode();
deleteKey(key);
}
/**
*
* @param key 根据key,找到插入位置
* @param val 插入元素
*/
public void insert(Integer key, V val) {
Node<Integer, V> leafNode = searchNode(key);
SearchResult search = leafNode.search(key);
if (search.isExist()) {
return;
} else {
//需要插入的key在树中不存在
int insertIndex = search.getInsertIndex();
List<Entry<Integer, V>> entries = leafNode.getEntries();
Entry<Integer, V> newEntry = newEntry(key, val);
entries.add(insertIndex, newEntry);
loopChangeParent(leafNode);
if (entries.size() <= this.degree) {
return;
} else {
splitNode(leafNode);
}
}
}
/**
* 从head开始查找key,找到key对应的叶子节点结束
* 在没有插入的时候,没有叶子节点,自己造一个叶节点嘛
* @param key
* @return
*/
private Node<Integer, V> searchNode(Integer key) {
if (head.isLeaf()) {
return head;
}
Node<Integer, V> node = head;
//非叶子节点时循环,跳出循环时,说明找到了叶子节点
while (!node.isLeaf()){
SearchResult search = node.search(key);
int index = search.getSearchIndex();
node = node.getNodeList().get(index);
}
return node;
}
public boolean isExist(Integer key) {
Node<Integer, V> leafNode = searchNode(key);
SearchResult search = leafNode.search(key);
return search.isExist();
}
/**
* 如果node.entries的最后一个entry和node.parent.entries的最后一个entry不同,则需要变更
* @param node
*/
private void loopChangeParent(Node<Integer, V> node) {
if (node.getParent() == null) {
return;
}
List<Entry<Integer, V>> parentEntries = node.getParent().getEntries();
List<Entry<Integer, V>> entries = node.getEntries();
// if (parentEntries.size() == 0) {
// parentEntries.add(entries.get(entries.size() - 1));
// return;
// }
Entry<Integer, V> parentLastEntry = parentEntries.get(parentEntries.size() - 1);
Entry<Integer, V> lastEntry = entries.get(entries.size() - 1);
if (parentLastEntry == lastEntry) {
return;
}
parentEntries.set(node.getNodeIndex(), lastEntry);
loopChangeParent(node.getParent());
}
/**
* 节点分裂
* @param node 需要分裂的节点
* 当node为head节点时 生成newHead和newNode
* head为叶子节点
* 1)newNode.setParent(newHead)
* 2)half个entry需要移动到newHead
* 3)newNode.setLeftNode(node)
* 4)分别将node和newNode的最后一个Entry加入到newHead的entries,并且将node,newNode加入到newHead的nodeList中
* 4)node.setRightNode(newNode)
* head为非叶子节点
* 1)newNode.setParent(newHead)
* 2)half个entry需要移动
* 3)half个node需要移动,且它们的父节点要指向newNode,它们的NodeIndex也需要变更
* 当node不为head节点时 生成newNode
* 叶子节点分裂
* 1)newNode.setParent(node.getParent())
* 2)half个entry需要移动
* 3)如果原本存在右节点,则需完成newNode.setRightNode和rightNode.setLeftNode
* 4)newNode.setNodeIndex(node.getNodeIndex() + 1)
* 非叶子节点分裂
* 1)newNode.setParent(node.getParent())
* 2)half个entry需要移动
* 3)half个node需要移动,且它们的父节点要指向newNode,它们的NodeIndex也需要变更
*
*/
private void splitNode(Node<Integer, V> node) {
if (node == head) {
if (node.isLeaf()) {
//分裂节点为head,会生成两个新节点
Node<Integer, V> newNode = newLeafNode();
Node<Integer, V> newHead = newBranchNode();
// ===================newNode的赋值过程===================
newNode.setParent(newHead);
newNode.setNodeIndex(1);
for (int i = 0 ; i < half; i++) {
newNode.getEntries().add(0,node.getEntries().get(this.degree - i));
node.getEntries().remove(this.degree - i);
}
newNode.setLeftNode(node);
//===================newHead节点的赋值过程===================
//newHead.setParent(null);
//newHead.setNodeIndex(-1);
newHead.getEntries().add(node.getEntries().get(node.getEntries().size() - 1));
newHead.getEntries().add(newNode.getEntries().get(node.getEntries().size() - 1));
newHead.getNodeList().add(node);
newHead.getNodeList().add(newNode);
// ===================head节点的赋值过程===================
node.setParent(newHead);
node.setNodeIndex(0);
node.setRightNode(newNode);
//===================head重新指向===================
head = newHead;
} else {
//分裂节点为head,会生成两个新节点
Node<Integer, V> newNode = newBranchNode();
Node<Integer, V> newHead = newBranchNode();
newNode.setParent(newHead);
newNode.setNodeIndex(1);
// ===================newNode的赋值过程===================
newNode.setParent(newHead);
newNode.setNodeIndex(1);
for (int i = 0 ; i < half; i++) {
newNode.getEntries().add(0,node.getEntries().get(this.degree - i));
node.getEntries().remove(this.degree - i);
newNode.getNodeList().add(0, node.getNodeList().get(this.degree - i));
node.getNodeList().get(this.degree - i).setParent(newNode);
node.getNodeList().remove(this.degree - i);
}
changeRightNodeIndex(newNode.getNodeList().get(0), 0);
newNode.setLeftNode(node);
//===================newHead节点的赋值过程===================
//newHead.setParent(null);
//newHead.setNodeIndex(-1);
newHead.getEntries().add(node.getEntries().get(node.getEntries().size() - 1));
newHead.getEntries().add(newNode.getEntries().get(node.getEntries().size() - 1));
newHead.getNodeList().add(node);
newHead.getNodeList().add(newNode);
// ===================head节点的赋值过程===================
node.setParent(newHead);
node.setNodeIndex(0);
//===================head重新指向===================
head = newHead;
}
} else {
//分裂节点不为head,只会生成一个节点,这个节点可能时叶子节点,也可能时非叶子节点
if (node.isLeaf()) {
//node为叶子节点,则新生成一个叶子节点
Node<Integer, V> newNode = newLeafNode();
// ===================newNode的赋值过程===================
newNode.setParent(node.getParent());
newNode.setNodeIndex(node.getNodeIndex() + 1);
for (int i = 0; i < half; i++) {
newNode.getEntries().add(0,node.getEntries().get(this.degree - i));
node.getEntries().remove(this.degree - i);
}
newNode.setLeftNode(node);//完成newNode的左指向
Node<Integer, V> rightNode = node.getRightNode();
if (rightNode != null) {//如果小于,说明node存在右节点
newNode.setRightNode(rightNode);//完成newNode的右指向
rightNode.setLeftNode(newNode);
//此外从node第一个右节点开始(包括第一个),所有的右节点的nodeIndex都需要修改
if (isRightNodeInCommonParent(node, rightNode)) {
//如果rightNode和node在同一个父节点下
changeRightNodeIndex(rightNode, node.getNodeIndex() + 2);
}
}
// ===================node.parent节点的赋值过程===================
Node<Integer, V> parent = node.getParent();
parent.getEntries().set(node.getNodeIndex(), node.getEntries().get(node.getEntries().size() - 1));
parent.getEntries().add(node.getNodeIndex() + 1, newNode.getEntries().get(newNode.getEntries().size() - 1));
parent.getNodeList().add(node.getNodeIndex() + 1, newNode);
// ===================node节点的赋值过程===================
node.setRightNode(newNode);
} else {
//node为非叶子节点,则新生成一个非叶子节点
Node<Integer, V> newNode = newBranchNode();
// ===================叶子节点的赋值过程===================
newNode.setParent(node.getParent());
newNode.setNodeIndex(node.getNodeIndex() + 1);
for (int i = 0; i < half; i++) {
newNode.getEntries().add(0, node.getEntries().get(this.degree - i));
node.getEntries().remove(this.degree - i);
Node<Integer, V> halfNode = node.getNodeList().get(this.degree - i);
halfNode.setParent(newNode);
newNode.getNodeList().add(0,node.getNodeList().get(this.degree - i));
node.getNodeList().remove(this.degree - i);
}
changeRightNodeIndex(newNode.getNodeList().get(0), 0);
// ===================node.parent节点的赋值过程===================
Node<Integer, V> parent = node.getParent();
parent.getEntries().add(node.getNodeIndex(), node.getEntries().get(half - 1));
parent.getNodeList().add(node.getNodeIndex() + 1,newNode);
changeRightNodeIndex(newNode, newNode.getNodeIndex());
}
if (node.getParent().getEntries().size() > this.degree) {
splitNode(node.getParent());
}
}
}
/**
* 判别rightNode是否是node同一个父节点下的右节点
* @param node
* @param rightnode
* @return
*/
private boolean isRightNodeInCommonParent(Node<Integer, V> node, Node<Integer, V> rightnode) {
if (!node.isLeaf()) {
throw new RuntimeException(node.getClass() + "is not leafNode, can't identify");
}
if (node.getNodeIndex() == node.getParent().getNodeList().size() - 1) {
return false;
}
return node.getParent().getNodeList().get(node.getNodeIndex() + 1) == rightnode;
}
/**
* 判别leftNode是否是node同一个父节点下的左节点
* @param node
* @param leftnode
* @return
*/
private boolean isLeafNodeInCommonParent(Node<Integer, V> node, Node<Integer, V> leftnode) {
if (!node.isLeaf()) {
throw new RuntimeException(node.getClass() + "is not leafNode, can't identify");
}
if (node.getNodeIndex() == 0) {
return false;
}
return node.getParent().getNodeList().get(node.getNodeIndex() - 1) == leftnode;
}
/**
* 设置node在parent中的nodeIndex,此外在同一个parent下的所有右兄弟节点的nodeIndex都要从startNodeIndex开始依次+1
* 例如
* K0-》index:0 K1-》index:1 K2-》index:2 K3-》index:3
* K1节点被删除了,那么再执行subRightNodeIndex(K2, 1)
* ===》
* K0-》index:0 K2-》index:1 K3-》index:2
* 也就是说将
* k2.nodeIndex = nodeIndex;
* K3.nodeIndex = nodeIndex + 1;
*
* @param node
*/
private void changeRightNodeIndex(Node<Integer, V> node, Integer startNodeIndex) {
List<Node<Integer, V>> parentNodeList = node.getParent().getNodeList();
int nodeIndex = -1;
for (int i = 0; i < parentNodeList.size(); i++) {
if (node == parentNodeList.get(i)) {
nodeIndex = i;
break;
}
}
if (nodeIndex == -1) {
throw new RuntimeException("nodeIndex = -1");
}
for (int i = nodeIndex; i < parentNodeList.size(); i++) {
Node<Integer, V> rightNode = parentNodeList.get(i);
rightNode.setNodeIndex(startNodeIndex++);
}
}
/**
* 层序遍历输出
* 9-18-27
* / | \
* 3-6-9 12-15-18 21-24-27
* / | \ / | \ / | \
* 1-2-3 4-5-6 7-8-9 10-11-12 13-14-15 16-17-18 19-20-21 22-23-24 25-26-27
*
* print输出
* 9-18-27
* 3-6-9 12-15-18 21-24-27
* 1-2-3 4-5-6 7-8-9 10-11-12 13-14-15 16-17-18 19-20-21 22-23-24 25-26-27
*/
public void print() {
Queue<Pair<Node<Integer, V>, Integer>> queue = new LinkedList<>();
StringBuilder sb = new StringBuilder();
ArrayList<Pair<Node<Integer, V>, Integer>> list = new ArrayList<>();
queue.offer(new Pair<>(this.head, 0));
while (!queue.isEmpty()) {
Pair<Node<Integer, V>, Integer> pair = queue.poll();
list.add(pair);
Node<Integer, V> node = pair.getKey();
if (!node.isLeaf()) {
for (int i = 0; i < node.getNodeList().size(); i++) {
queue.offer(new Pair<>(node.getNodeList().get(i), pair.getValue() + 1));
}
}
}
for (int i = 0; i < list.size(); i++) {
Pair<Node<Integer, V>, Integer> pair = list.get(i);
List<Entry<Integer, V>> entries = pair.getKey().getEntries();
if (i > 0) {
Integer afterVal = list.get(i - 1).getValue();
Integer val = list.get(i).getValue();
if (afterVal != val) {
sb.append("\r\n");
} else {
sb.append(" ");
}
}
for (int j = 0; j < entries.size(); j++) {
sb.append(entries.get(j).getKey());
if (j < entries.size() -1) {
sb.append("-");
}
}
//sb.append(":"+pair.getValue());
}
System.out.println(sb.toString());
}
public void printInfo() {
Queue<Pair<Node<Integer, V>, Integer>> queue = new LinkedList<>();
StringBuilder sb = new StringBuilder();
ArrayList<Pair<Node<Integer, V>, Integer>> list = new ArrayList<>();
queue.offer(new Pair<>(this.head, 0));
while (!queue.isEmpty()) {
Pair<Node<Integer, V>, Integer> pair = queue.poll();
list.add(pair);
Node<Integer, V> node = pair.getKey();
if (!node.isLeaf()) {
for (int i = 0; i < node.getNodeList().size(); i++) {
queue.offer(new Pair<>(node.getNodeList().get(i), pair.getValue() + 1));
}
}
}
for (int i = 0; i < list.size(); i++) {
Pair<Node<Integer, V>, Integer> pair = list.get(i);
List<Entry<Integer, V>> entries = pair.getKey().getEntries();
if (i > 0) {
Integer afterVal = list.get(i - 1).getValue();
Integer val = list.get(i).getValue();
if (afterVal != val) {
sb.append("\r\n");
} else {
sb.append(" ");
}
}
for (int j = 0; j < entries.size(); j++) {
sb.append(entries.get(j).getKey());
if (j < entries.size() -1) {
sb.append("-");
}
}
Node<Integer, V> node = pair.getKey();
Node<Integer, V> parent = node.getParent();
if (parent != null) {
sb.append("->parent:"+parent.toString().replace("com.thinking.tree.Node",""));
} else {
sb.append("->parent:"+parent);
}
sb.append(",this:" + node.toString().replace("com.thinking.tree.Node",""));
sb.append(",index:" + node.getNodeIndex());
if (node.isLeaf()) {
if (node.getLeftNode() != null) {
sb.append(",left:"+node.getLeftNode().toString().replace("com.thinking.tree.Node",""));
} else {
sb.append(",left:"+node.getLeftNode());
}
if (node.getRightNode() != null) {
sb.append(",right:" + node.getRightNode().toString().replace("com.thinking.tree.Node",""));
} else {
sb.append(",right:" + node.getRightNode());
}
}
}
System.out.println(sb.toString());
}
/**
* 依据key删除
* @param key
*/
public void deleteKey(Integer key) {
Node<Integer, V> leafNode = searchNode(key);
SearchResult search = leafNode.search(key);
if (!search.isExist()) {
return;
} else {
//需要删除的key在树中存在
int searchIndex = search.getSearchIndex();
List<Entry<Integer, V>> entries = leafNode.getEntries();
entries.remove(searchIndex);
loopChangeParent(leafNode);
if (entries.size() >= (this.degree + 1) / 2 || leafNode == head) {
return;
} else {
// !( entries.size() >= (this.degree + 1) / 2 || leafNode == head )
// 可得 entries.size() < (this.degree + 1) / 2 && leafNode != head
// 再由 leafNode != head 和B+树的定义(非叶根节点至少有两棵子树)可得,leaf要么存在左节点,要么存在右节点
// 这个性质后续代码会用到
borrowAndcombineNode(leafNode);
}
}
}
/**
* 从node开始借entry,和合并
* @param node
*/
private void borrowAndcombineNode(Node<Integer, V> node) {
Node<Integer, V> leftNode = getLeftNodeInCommonParent(node);
Node<Integer, V> rightNode = getRightNodeInCommonParent(node);
if (node.isLeaf()) {
if (leftNode != null && leftNode.getEntries().size() > half) {//找左借
node.getEntries().add(0, leftNode.getEntries().get(leftNode.getEntries().size() - 1));
leftNode.getEntries().remove(leftNode.getEntries().size() - 1);
loopChangeParent(leftNode);
} else if (rightNode != null && rightNode.getEntries().size() > half) {//找右借
node.getEntries().add(rightNode.getEntries().get(0));
rightNode.getEntries().remove(0);
loopChangeParent(node);//右借之后,node.entries的最后一个元素变了
} else {//左右都不能借,那只能合并了
combineNode(node);
}
}
}
/**
* 得到node同一个parent下的leftNode
* @param node
* @return
*/
private Node<Integer, V> getLeftNodeInCommonParent(Node<Integer, V> node) {
if (node.getParent() == null || node == node.getParent().getNodeList().get(0)) {
return null;
}
return node.getParent().getNodeList().get(node.getNodeIndex() - 1);
}
/**
* 得到node同一个parent下的rightNode
* @param node
* @return
*/
private Node<Integer, V> getRightNodeInCommonParent(Node<Integer, V> node) {
if (node.getParent() == null || node == node.getParent().getNodeList().get(node.getParent().getNodeList().size() - 1)) {
return null;
}
return node.getParent().getNodeList().get(node.getNodeIndex() + 1);
}
/**
* 当这个方法执行的时候,一定存在叶子节点的合并,可能存在非叶子节点的合并
* 节点合并
* 叶子节点的合并
* 合并到左节点中(同一个父节点),父节点的entries.size和nodeList.size()都要-1,层数是否降低
* 合并到右节点中(同一个父节点),父节点的entries.size和nodeList.size()都要-1,层数是否降低
* 非叶子节点
* 非叶子节点的不合并(当node.entries.size() >= half)
* 非叶子节点的合并(当node.entries.size() < half)
* 合并到左节点中(同一个父节点),父节点的entries.size和nodeList.size()都要-1,层数是否降低
* 合并到右节点中(同一个父节点),父节点的entries.size和nodeList.size()都要-1,层数是否降低
* @param node
*/
private void combineNode(Node<Integer, V> node) {
if (node.getEntries().size() >= half || node == head) {
return;
}
Node<Integer, V> parent = node.getParent();
Node<Integer, V> leftNode = getLeftNodeInCommonParent(node);//同一个父节点中的左节点
Node<Integer, V> rightNode = getRightNodeInCommonParent(node);//同一个父节点中的右节点
if (node.isLeaf()) {
Node<Integer, V> leftRealNode = node.getLeftNode();//node的左节点
Node<Integer, V> rightRealNode = node.getRightNode();//node的右节点
if (leftNode != null) {//左节点都不为空,元素移动到左节点
//===================node节点的赋值过程===================
node.setParent(null);
for (int i = 0; i < half - 1; i++) {
leftNode.getEntries().add(node.getEntries().get(0));
node.getEntries().remove(0);
}
node.setLeftNode(null);
node.setRightNode(null);
//===================parent节点的赋值过程===================
parent.getEntries().remove(node.getNodeIndex() - 1);
parent.getNodeList().remove(node.getNodeIndex());
//===================左右节点的赋值过程===================
if (rightRealNode != null) {
leftNode.setRightNode(rightRealNode);
rightRealNode.setLeftNode(leftNode);
} else {
leftRealNode.setRightNode(null);
}
if (rightNode != null) {
changeRightNodeIndex(rightNode, rightNode.getNodeIndex() -1);
}
if (canOrNotReduceLayers(leftNode)) { return; }
} else{//左节点为空,右节点不为空,元素移动到右节点
//===================node节点的赋值过程===================
node.setParent(null);
for (int i = 0; i < half - 1; i++) {
rightNode.getEntries().add(0, node.getEntries().get(node.getEntries().size() - 1));
node.getEntries().remove(node.getEntries().size() - 1);
}
node.setLeftNode(null);
node.setRightNode(null);
//===================parent节点的赋值过程===================
parent.getEntries().remove(node.getNodeIndex());
parent.getNodeList().remove(node.getNodeIndex());
//===================左右节点的赋值过程===================
if (leftRealNode != null) {
rightNode.setLeftNode(leftRealNode);
leftRealNode.setRightNode(rightNode);
} else {
rightNode.setLeftNode(null);
}
changeRightNodeIndex(rightNode, rightNode.getNodeIndex() - 1);
if (canOrNotReduceLayers(rightNode)) {
return;
}
}
} else {//合并的节点为非叶子节点
if (leftNode != null && leftNode.getEntries().size() > half) {//从左边借
leftBorrow(node);
} else if (rightNode != null && rightNode.getEntries().size() > half) {//从右边借
rightBorrow(node);
} else {//两边都不能借,只能合并
//优先找左边合并
if (node.getNodeIndex() > 0) {//左旋,和左节点合并
leftRotate(node);
if(canOrNotReduceLayers(leftNode)) {
return;
}
} else {//右旋,和右节点合并
rightRotate(node);
if(canOrNotReduceLayers(rightNode)) {
return;
}
}
}
}
combineNode(parent);
}
/**
* @param node 节点合并完成判断是否需要降层数,每当层数降低之后。说明树结构已经符合B+树定义(已经稳定)
*/
private boolean canOrNotReduceLayers(Node<Integer, V> node) {
if (node.getParent().getEntries().size() == 1 && node.getParent() == head) {
//head的设置
head.getEntries().remove(0);
head.getNodeList().remove(0);
//node的设置
node.setParent(null);
node.setNodeIndex(-1);
if (node.getNodeList().get(0) == null) {
node.setLeaf(true);
}
head = node;
return true;
}
return false;
}
/**
* 右借
* @param node node.getNodeList().size() < half的节点
*/
private void leftBorrow(Node<Integer, V> node) {
Node<Integer, V> parent = node.getParent();
Node<Integer, V> leftNode = parent.getNodeList().get(node.getNodeIndex() - 1);
List<Entry<Integer, V>> entries = node.getEntries();
entries.add(0, leftNode.getEntries().get(leftNode.getEntries().size() - 1));
leftNode.getEntries().remove(leftNode.getEntries().size() - 1);
List<Node<Integer, V>> nodeList = node.getNodeList();
Node<Integer, V> leftNodeLastNode = leftNode.getNodeList().get(leftNode.getNodeList().size() - 1);
nodeList.add(0, leftNodeLastNode);
leftNode.getNodeList().remove(leftNode.getNodeList().size() - 1);
leftNodeLastNode.setParent(node);
leftNodeLastNode.setNodeIndex(0);
changeRightNodeIndex(node.getNodeList().get(1), 1);
loopChangeParent(leftNode);
}
/**
* 左借
* @param node node.getNodeList().size() < half的节点
*/
private void rightBorrow(Node<Integer, V> node) {
Node<Integer, V> parent = node.getParent();
Node<Integer, V> rightNode = parent.getNodeList().get(node.getNodeIndex() + 1);
List<Entry<Integer, V>> entries = node.getEntries();
entries.add(rightNode.getEntries().get(0));
rightNode.getEntries().remove(0);
List<Node<Integer, V>> nodeList = node.getNodeList();
Node<Integer, V> rightNodeFirstNode = rightNode.getNodeList().get(0);
nodeList.add(rightNodeFirstNode);
rightNode.getNodeList().remove(0);
rightNodeFirstNode.setParent(node);
rightNodeFirstNode.setNodeIndex(nodeList.size() - 1);
changeRightNodeIndex(rightNode.getNodeList().get(0), 0);
loopChangeParent(node);
}
private boolean isExistRightNodeInCommonParent(Node<Integer, V> node) {
return node.getNodeIndex() < node.getParent().getNodeList().size() - 1;
}
private boolean isExistLeftNodeInCommonParent(Node<Integer, V> node) {
return node.getNodeIndex() > 0;
}
/**
* 左旋,和左节点合并
* @param node node.getNodeList().size() < half的节点
*/
private void leftRotate(Node<Integer, V> node) {
Node<Integer, V> parent = node.getParent();
Node<Integer, V> leftNode = parent.getNodeList().get(node.getNodeIndex() - 1);
Node<Integer, V> rightNode = null;
if (isExistRightNodeInCommonParent(node)) {
rightNode = parent.getNodeList().get(node.getNodeIndex() + 1);
}
for (int i = 0; i < half - 1; i++) {
leftNode.getEntries().add(node.getEntries().get(0));
node.getEntries().remove(0);
Node<Integer, V> nodeFirstNode = node.getNodeList().get(0);
nodeFirstNode.setParent(leftNode);
nodeFirstNode.setNodeIndex(leftNode.getNodeList().get(leftNode.getNodeList().size() - 1).getNodeIndex() + 1);
leftNode.getNodeList().add(nodeFirstNode);
node.getNodeList().remove(0);
}
if (isExistRightNodeInCommonParent(node)) {
changeRightNodeIndex(rightNode, rightNode.getNodeIndex() -1);
}
node.setParent(null);
parent.getEntries().remove(node.getNodeIndex() - 1);
parent.getNodeList().remove(node.getNodeIndex());
loopChangeParent(leftNode);
}
/**
* 右旋,和右节点合并
* @param node node.getNodeList().size() < half的节点
*/
private void rightRotate(Node<Integer, V> node) {
Node<Integer, V> parent = node.getParent();
List<Node<Integer, V>> parentNodeList = parent.getNodeList();
Node<Integer, V> rightNode = parentNodeList.get(node.getNodeIndex() + 1);
// Node rightNode = parent.getNodeList().get(node.getNodeIndex() + 1);
for (int i = 0; i < half - 1; i++) {
rightNode.getEntries().add(0, node.getEntries().get(node.getEntries().size() - 1));
node.getEntries().remove(node.getEntries().size() - 1);
Node<Integer, V> nodeLastNode = node.getNodeList().get(node.getNodeList().size() - 1);
nodeLastNode.setParent(rightNode);
//nodeLastNode.setNodeIndex(-1);后面会设置
rightNode.getNodeList().add(0, nodeLastNode);
node.getNodeList().remove(node.getNodeList().size() - 1);
}
changeRightNodeIndex(rightNode.getNodeList().get(0), 0);
changeRightNodeIndex(rightNode, rightNode.getNodeIndex() -1);
node.setParent(null);
parent.getEntries().remove(node.getNodeIndex());
parent.getNodeList().remove(node.getNodeIndex());
}
public List<V> selectGreaterAndEqual(Integer key){
Node<Integer, V> leafNode = searchNode(key);
SearchResult search = leafNode.search(key);
ArrayList<V> resList = new ArrayList<>();
if (search.isExist()) {
int insertIndex = search.getInsertIndex();
List<Entry<Integer, V>> entries = leafNode.getEntries();
for (int i = insertIndex; i < entries.size() - 1; i++) {
resList.add(entries.get(i).getValue());
}
while (leafNode.getRightNode() != null) {
Node<Integer, V> rightNode = leafNode.getRightNode();
List<Entry<Integer, V>> rightNodeEntries = rightNode.getEntries();
for (int i = 0; i < rightNodeEntries.size() - 1; i++) {
resList.add(rightNodeEntries.get(i).getValue());
}
leafNode = rightNode;
}
}
return resList;
}
public List<V> selectLessAndEqual(Integer key){
Node<Integer, V> leafNode = searchNode(key);
SearchResult search = leafNode.search(key);
ArrayList<V> resList = new ArrayList<>();
if (search.isExist()) {
int insertIndex = search.getInsertIndex();
List<Entry<Integer, V>> entries = leafNode.getEntries();
for (int i = insertIndex; i >= 0; i--) {
resList.add(entries.get(i).getValue());
}
while (leafNode.getLeftNode() != null) {
Node<Integer, V> leftNode = leafNode.getLeftNode();
List<Entry<Integer, V>> leftNodeEntries = leftNode.getEntries();
for (int i = leftNodeEntries.size() - 1; i >= 0; i--) {
resList.add(leftNodeEntries.get(i).getValue());
}
leafNode = leftNode;
}
}
return resList;
}
}
package com.thinking.tree;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class BPTTest {
public static void main(String[] args) {
// test1();
// test2();
// test3();
// test4();
// test5();
// test6();
// test7();
// test8();
// test9();
//test10();
//test11();
//test12();
test13();
}
private static void test1() {
BPlusTree<Integer> tree = new BPlusTree<>(5);
for (int i = 0; i <= 130; i++) {
System.out.println("插入 "+ i +" 之后: ");
tree.insert(i,i);
tree.print();
}
for (int i = 0; i <= 130; i++) {
System.out.println("删除 "+ i +" 之后: ");
tree.deleteKey(130 - i);
tree.print();
}
}
private static void test2() {
BPlusTree<Integer> tree = new BPlusTree<>(5);
Random random = new Random();
for (int i = 0; i < 1000; i++) {
int key = random.nextInt(100);
System.out.println("No." + i + " 插入 "+ key +" 之后: ");
tree.insert(key,key);
tree.print();
}
for (int i = 0; i < 1000; i++) {
int key = random.nextInt(100);
System.out.println("No." + i + " 删除 "+ key +" 之后: ");
tree.deleteKey(key);
tree.print();
}
}
private static void test3() {
ArrayList<Entry<Integer, Integer>> entries = new ArrayList<>(1000000);
for (int i = 1; i <= 1000000; i++) {
entries.add(new Entry<>(i,i));
}
long startTime = System.currentTimeMillis();
for (Entry<Integer, Integer> entry : entries) {
if (entry.getKey() == 1000000/2) break;
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
private static void test4() {
BPlusTree<Integer> tree = new BPlusTree<>(1000);
for (int i = 1; i <= 1000000/2; i++) {
tree.insert(i,i);
}
for (int i = 1000000/2 + 2; i <= 1000000; i++) {
tree.insert(i,i);
}
long startTime = System.currentTimeMillis();
System.out.println(tree.isExist(1000000 / 2 + 1));
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
private static void test5() {
BPlusTree<Integer> tree = new BPlusTree<>(5);
for (int i = 1; i <= 60; i++) {
tree.insert(i,i);
}
tree.print();
}
private static void test6() {
BPlusTree<Integer> tree = new BPlusTree<>(5);
for (int i = 1; i <= 13; i++) {
tree.insert(i,i);
}
tree.print();
int deleteKeyKey = 8;
tree.deleteKey(deleteKeyKey);
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.print();
}
private static void test7() {
BPlusTree<Integer> tree = new BPlusTree<>(5);
for (int i = 0; i <= 130; i += 10) {
tree.insert(i,i);
}
tree.insert(19,19);
tree.print();
int deleteKeyKey = 80;
tree.deleteKey(deleteKeyKey);
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.print();
}
private static void test8() {
BPlusTree<Integer> tree = new BPlusTree<>(5);
String flag = "print";
for (int i = 0; i <= 400; i += 10) {
tree.insert(i,i);
}
for (int i = 71; i < 79; i++) {
tree.insert(i,i);
}
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
int deleteKeyKey = 80;
tree.deleteKey(deleteKeyKey);
System.out.println("删除 " +deleteKeyKey+" 之后:");
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 78;
tree.deleteKey(deleteKeyKey);
System.out.println("删除 " +deleteKeyKey+" 之后:");
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 100;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 74;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 0;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
}
private static void test9() {
BPlusTree<Integer> tree = new BPlusTree<>(5);
int num = 18;
String flag = "printInfo";
int deleteKeyKey = -1;
for (int i = 0; i < num; i++) {
tree.insert(i, i);
}
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 0;
tree.deleteKey(deleteKeyKey);
System.out.println("删除 " +deleteKeyKey+" 之后:");
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
}
private static void test10() {
BPlusTree<Integer> tree = new BPlusTree<>(5);
String flag = "printInfo";
int deleteKeyKey = -1;
for (int i = 1; i <= 60; i++) {
tree.insert(i, i);
}
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
tree.deleteKey(4);
tree.deleteKey(2);
tree.deleteKey(3);
tree.deleteKey(5);
tree.deleteKey(1);
tree.deleteKey(6);
deleteKeyKey = 260;
tree.deleteKey(deleteKeyKey);
System.out.println("删除 " +deleteKeyKey+" 之后:");
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
}
private static void test11() {
BPlusTree<Integer> tree = new BPlusTree<>(5);
String flag = "print";
int deleteKeyKey = -1;
for (int i = 1; i <= 36; i++) {
tree.insert(i, i);
}
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 1;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 36;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 2;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 3;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 4;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 35;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 34;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 33;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 5;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 6;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 7;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 30;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 31;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 32;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 8;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 9;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
deleteKeyKey = 10;
System.out.println("删除 " +deleteKeyKey+" 之后:");
tree.deleteKey(deleteKeyKey);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
// deleteKeyKey = 11;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 12;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 13;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 29;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 28;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 27;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 14;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 15;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 16;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 16;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 26;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 25;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 24;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 17;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 18;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 19;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 23;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 22;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 21;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
//
// deleteKeyKey = 20;
// System.out.println("删除 " +deleteKeyKey+" 之后:");
// tree.deleteKey(deleteKeyKey);
// if ("print".equals(flag)) {
// tree.print();
// } else {
// tree.printInfo();
// }
}
private static void test12() {
BPlusTree<Integer> tree = new BPlusTree<>(5);
String flag = "print";
int deleteKeyKey = -1;
for (int i = 1; i <= 36; i++) {
tree.insert(i, i);
}
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
// List list = tree.selectGreaterAndEqual(10);
// StringBuilder sb = new StringBuilder();
// for (Integer i : list) {
// sb.append(i).append(" ");
// }
// System.out.println(sb.toString());
List<Integer> list = tree.selectLessAndEqual(10);
StringBuilder sb = new StringBuilder();
for (Integer i : list) {
sb.append(i).append(" ");
}
System.out.println(sb.toString());
}
private static void test13() {
BPlusTree<Integer> tree = new BPlusTree<>(5);
String flag = "print";
for (int i = 1; i <= 36; i++) {
tree.insert(i);
}
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
for (int i = 0; i <= 36; i++) {
System.out.println("删除 " + i +" 之后:");
tree.delete(i);
if ("print".equals(flag)) {
tree.print();
} else {
tree.printInfo();
}
}
}
}
距离上次写B树已经过去1年了,最近花了10天写完这东西,基本上就是不停画图,腰酸背疼的。如果对你有用,那我也挺高兴的,如果能帮我点个赞,那我更高兴了。写完这篇,我也要忙着换工作了,下次写不知道是啥时候了。
感谢以下博客和软件:
王道–数据结构(bilibili视频)
B+树及插入和删除操作详解
聊聊MongoDB(一):MongoDB体系结构与底层原理
画图软件drawio