一、介绍
- B+树索引是B+树在数据库中的一种实现,是最常见也是数据库中使用最为频繁的一种索引。
- B+树中的B代表平衡(balance)。(平衡多路查找树)
- B+树是从最早的平衡二叉树演化而来的。
二、B-Tree
- B-Tree是为磁盘等外存储设备设计的一种平衡查找树。
- 每个节点最多有m个孩子。
- 除了根节点和叶子节点外,其它每个节点至少有Ceil(m/2)个孩子。
- 若根节点不是叶子节点,则至少有2个孩子
- 所有叶子节点都在同一层,且不包含其它关键字信息
- 每个非终端节点包含n个关键字信息(P0,P1,…Pn, k1,…kn)
- 关键字的个数n满足:ceil(m/2)-1 <= n <= m-1
- ki(i=1,…n)为关键字,且关键字升序排序。
- Pi(i=1,…n)为指向子树根节点的指针。P(i-1)指向的子树的所有节点关键字均小于ki,但都大于k(i-1)
(个人理解:关键字上的数据存储在本节点上,每个范围内的数据存储在下一个节点上,叶子节点只存储数据)
如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,进而影响查询效率。
原文 https://blog.csdn.net/baidu_29961857/article/details/89879739
package com.numberone.tree;
import java.util.LinkedList;
/**
* Created on 2020/1/7.
*
* @author Gray
* @since 1.0
*/
public class BTree<K extends Comparable<K>,V> {
private final class Node{
int keynum;
Node parent;
LinkedList<Entry> entries;
LinkedList<Node> childs;
}
private final class Entry{
K k;
V v;
public Entry(){}
public Entry(K k, V v) {
this.k = k;
this.v = v;
}
@Override
public String toString() {
return "{"+ k +
"," + v +
'}';
}
}
private final class Result{
Node ptr;int i;boolean tag;
public Result(Node ptr, int i, boolean tag) {
this.ptr = ptr;
this.i = i;
this.tag = tag;
}
}
private int degree;
private Node root;
public BTree(int degree, Node root) {
this.degree = degree;
this.root = root;
}
private Result searchTree(Node T,K k){
Node p=T,q=null;
boolean found=false;
int i=0;
while(p!=null && !found){
i=search(p,k);
if(i>0 && eq(k,p.entries.get(i).k))found=true;
else{
q=p;
p=p.childs.get(i);
}
}
if(found)return new Result(p,i,true);
else return new Result(q,i,false);
}
//index
private int search(Node p,K k){
int j=0;
for(;j<p.keynum;j++){
if(lt(k,p.entries.get(j+1).k))break;
}
return j;
}
public void put(K k,V v){
Entry entry=new Entry(k,v);
Result result=searchTree(root,entry.k);
if(!result.tag) insertBTree(result.ptr,entry,result.i);
else{
result.ptr.entries.set(result.i,entry);
}
//result.ptr.entries.set(result.i,entry);
}
public void insertBTree(Node q,Entry entry,int i){
int s;Entry x=entry;Node ap=null,tmp=null;boolean finished=false;
while(q!=null && !finished){
insert(q,i,x,ap);
if(q.keynum<degree)finished=true;
else{
s=degree%2==0?degree/2:degree/2+1;
x=q.entries.get(s);
ap=new Node();
split(q,x,s,ap);
tmp=q;
q=q.parent;
if(q!=null){i=search(q,entry.k);}
}
}
if(!finished){
root=tmp;
newRoot(q,x,ap);
}
}
public void insert(Node q,int i,Entry entry,Node ap){
q.childs.add(i+1,ap);
q.entries.add(i+1,entry);
if(ap != null) ap.parent=q;
q.keynum++;
}
public void newRoot(Node q,Entry entry,Node ap){
q=new Node();
q.entries=new LinkedList<>();
q.childs=new LinkedList<>();
q.parent=null;
q.entries.add(null);
q.entries.add(entry);
q.keynum=1;
q.childs.add(root);
q.childs.add(ap);
for(int i=0;i<=q.keynum;i++){
if(q.childs.get(i)!=null){
q.childs.get(i).parent=q;
}
}
root=q;
}
public void split(Node q,Entry entry,int s,Node ap){
ap.childs=new LinkedList<>();
ap.entries=new LinkedList<>();
ap.entries.add(null);
ap.entries.addAll(q.entries.subList(s+1,degree+1));
ap.childs.add(q.childs.get(s));
ap.childs.addAll(q.childs.subList(s+1,degree+1));
ap.keynum=degree-s;
q.keynum=s-1;
for(int i=degree;i>q.keynum;i--){
q.entries.removeLast();
q.childs.removeLast();
}
for(int i=0;i<=ap.keynum;i++){
if(ap.childs.get(i)!=null){
ap.childs.get(i).parent=ap;
}
}
}
/*
delete---------------------------------
*/
public boolean deleteKey(K k){
Result result=searchTree(root,k);
if(result.tag) return deleteTree(result);
else return false;
}
public boolean deleteTree(Result result){
Node q=result.ptr;
Result minResult=null;
int i=0;
Node node=null;
if(q.childs.get(result.i)!=null){
minResult=searchMinKey(q);
}
if(minResult!=null){
node=minResult.ptr;
i=minResult.i;
}else{
node=result.ptr;
i=result.i;
}
//when the node and q refers to the same object exceptions accured
LinkedList<Entry> tmplist=new LinkedList<>();
tmplist.addAll(node.entries);
q.entries.remove(result.i);
q.entries.add(result.i,tmplist.get(i));
return delete(node ,i);
}
private boolean delete(Node q,int i){
int s,tag=0;
Node p=null,lc,rc;
s=degree%2==0?degree/2:(degree/2+1);
int order=-1;
p=q.parent;
if(p==null){
tag=1;
}else{
order=foundIndexOfParent(q,p);
if(q.keynum>=s){
tag=2;//delete the entry directyly
}else{
if(tag==0 && order<p.keynum && p.childs.get(order+1).keynum>=s){ tag=3; }
if(tag==0 && order>0 && p.childs.get(order-1).keynum>=s){ tag=4; }
if(tag==0 && order<p.keynum && p.childs.get(order+1).keynum==s-1){ tag=5; }
if(tag==0 && order>0 && p.childs.get(order-1).keynum==s-1){ tag=6; }
}
}
switch (tag){
case 0:return false;
case 1:
removeKeyAndChild(q,i);
if(q.keynum==1 && i==1) root=q.childs.get(0);
q.keynum--;
break;
case 2:
removeKeyAndCh