b 树 java_B+树java实现

package com.source;

import java.util.ArrayDeque;

import java.util.ArrayList;

import java.util.Deque;

import java.util.List;

import java.util.Random;

//定义B树结构

@SuppressWarnings("hiding")

public class MyBTree{

private static final int DEFAULT_T = 2;

// B树根节点

private BTNoderoot;

// 度数

private int t;

// 非根节点的最少关键字个数

private int minKeyNum;

// 非根节点的最大关键字个数

private int maxKeyNum;

// 定义树节点

private class BTNode{

// 关键字个数

public int n = 0;

// 存放关键字

public Listkeys = new

ArrayList(maxKeyNum);

// 存放孩子节点的指针

public List> children = new ArrayList>(

maxKeyNum + 1);

// 是否为叶子节点,初始化是叶子节点

public boolean isLeaf = true;

// 向树节点中插入元素

public void insertKey(int index, Object key) {

keys.add(index, key);

n++;

if (keys.size() > maxKeyNum) {

keys.remove(maxKeyNum);

}

}

// 在树节点中移除元素

public Object removeKey(int index) {

Object key = keys.remove(index);

n--;

return key;

}

// 添加孩子节点指针

public void insertChild(int index, BTNodechild)

{

children.add(index, child);

if (children.size() > maxKeyNum + 1) {

children.remove(maxKeyNum + 1);

}

}

// 移除孩子节点指针

public BTNoderemoveChild(int index) {

BTNodechild = children.remove(index);

return child;

}

}

public MyBTree() {

this(DEFAULT_T);

}

public MyBTree(int degree) {

if (degree < 2) {

t = DEFAULT_T;

}

this.t = degree;

this.minKeyNum = degree - 1;

this.maxKeyNum = 2 * degree - 1;

BTNodenode = new

BTNode();

this.root = node;

}

// 添加元素

public void insert(Object key) {

BTNoder = root;

// 若节点元素已满

if (root.n == maxKeyNum) {

BTNodenewRoot = new

BTNode();

root = newRoot;

newRoot.isLeaf = false;

// 添加原节点为孩子节点

newRoot.insertChild(0, r);

// 分裂孩子节点

sliptChild(newRoot, 0);

insertNoFull(newRoot, key);

} else

insertNoFull(r, key);

}

// 分裂节点

private void sliptChild(BTNodex, int index)

{

// 新增结点

BTNodenewNode = new

BTNode();

// 获取原父节点

BTNodey = x.children.get(index);

// 标记是否为叶子节点

newNode.isLeaf = y.isLeaf;

// 向新节点添加元素

for (int j = 0; j < minKeyNum; j++) {

// 从最小元素个数处开始添加

newNode.insertKey(j, y.keys.get(j + t));

}

// 如果原父节点不是叶子节点

if (!y.isLeaf) {

for (int j = 0; j < t; j++) {

newNode.insertChild(j, y.children.get(j + t));

}

}

// 修改节点元素个数

newNode.n = minKeyNum;

y.n = minKeyNum;

// 链接新节点

x.insertChild(index + 1, newNode);

// 添加新元素

x.insertKey(index, y.keys.get(minKeyNum));

}

// 将元素添加至未满的树节点中

private void insertNoFull(BTNodex, Object key)

{

int i = x.n - 1;

// 是叶子节点

if (x.isLeaf) {

while (i >= 0 && key.hashCode() <

x.keys.get(i).hashCode())

i--;

x.insertKey(i + 1, key);

} else {

// 非叶子节点,寻找添加位置

while (i >= 0 && key.hashCode() <

x.keys.get(i).hashCode())

i--;

i = i + 1;

// 若添加位置处元素已满,则分裂节点

if (x.children.get(i).n == maxKeyNum) {

sliptChild(x, i);

// 关键值大于分裂的一个节点

if (key.hashCode() > x.keys.get(i).hashCode())

i = i + 1;

}

insertNoFull(x.children.get(i), key);

}

}

// 删除元素

public boolean delete(Object key) {

return delete(root, key) != null ? true : false;

}

//从某个节点开始删除元素

private Object delete(BTNodex, Object key)

{

// 该过程需要保证,对非根节点执行删除操作时,其关键字个数至少为t。

// 获取节点的元素个数

int n = x.n;

// 断言机制,判断是否正确执行

assert n >= t || x == root;

int i = 0;

while (i < n && key.hashCode() >

x.keys.get(i).hashCode())

i++;

// 当前节点等于要删除的节点

if (i < n && key.equals(x.keys.get(i))) {

// 当前节点是叶子节点

if (x.isLeaf) {

// 直接删除关键字

x.removeKey(i);

}

else {

//获取两边子树根节点

BTNodelittle = x.children.get(i);

BTNodebigger = x.children.get(i + 1);

//左边节点个数满足度数要求

if (little.n >= t) {

// 小于关键值最大值

Object preKey = deleteMaxKey(little);

x.keys.set(i, preKey);

}

else if (bigger.n >= t) {

// 大于关键字最小值

Object nextKey = deleteMinKey(bigger);

x.keys.set(i, nextKey);

}

else {

// 合并节点

int ySize = little.n;

int zSize = bigger.n;

// little.insertKey(ySize, key);

// ySize++;

boolean isChildLeaf = little.isLeaf;

for (int j = 0; j < zSize; j++) {

// 大于关键字子树。添加到小于关键字的子树

little.insertKey(ySize, bigger.keys.get(j));

// 若不是叶节点,则添加孩子节点

if (!isChildLeaf) {

little.insertChild(ySize, bigger.children.get(j));

}

ySize++;

}

//若不是叶节点,添加最后一个指向孩子的指针

if (!isChildLeaf) {

little.insertChild(ySize, bigger.children.get(zSize -

1));

}

//删除节点以及对应的子节点

x.removeKey(i);

x.removeChild(i + 1);

if (x.n == 0) {

root = little;

}

// delete(little, key);

}

}

//删除节点成功

return key;

}

else if (x.isLeaf) {

// 没有找到该关键字,直接返回

return null;

}

// 当前节点不等于要删除的节点

else {

return delete(x.children.get(i), key);

}

}

//删除一个节点中最大的元素

private Object deleteMaxKey(BTNodex) {

int keyNum = x.n;

if (x.isLeaf) {

return x.removeKey(keyNum - 1);

}

else {

return delete(x,x.keys.get(x.n-1));

}

}

//删除一个节点中最小的元素

private Object deleteMinKey(BTNodex) {

//节点为叶节点

if (x.isLeaf) {

return x.removeKey(0);

}

else {

return delete(x,x.keys.get(0));

}

}

//是否包含某个元素

public boolean contains(Object object){

return contains(root, object);

}

// 从某节点开始是否包含某个元素

private boolean contains(BTNodebtnode,Object

object){

int index = findPosition(btnode, object, 0, btnode.n-1);

// 找到节点

if(btnode.keys.get(index).hashCode() ==

object.hashCode()){

System.out.println("Find \""+object+"\" at index -> "+

(index+1));

return true;

}

// 叶子节点,遍历结束

else if(btnode.isLeaf){

System.out.println("The BTree has no member values

\""+object+"\"!" );

return false;

}

// 非叶子节点

else if(btnode.keys.get(index).hashCode() <

object.hashCode()){

return contains(btnode.children.get(index+1),object);

}

else {

return contains(btnode.children.get(index),object);

}

}

//二分查找树节点

private int findPosition(BTNodebtnode,Object

object,int start,int end){

if(start >= end)

return start;

int middle = start+(end-start)/2;

if(btnode.keys.get(middle).hashCode() ==

object.hashCode())

return middle;

else if (btnode.keys.get(middle).hashCode() >

object.hashCode()) {

return findPosition(btnode, object, start, middle-1);

}

else {

return findPosition(btnode, object, middle+1, end);

}

}

// 返回B树中元素的个数

public int size(){

return count(root);

}

//统计某个节点下孩子个数

private int count(BTNodenode){

if(node.isLeaf)

return node.n;

int sum = node.n;

for(int index = 0;index <= node.n;++index){

sum += count( node.children.get(index) );

}

return sum;

}

//是否为空

public boolean isEmpty() {

if(root.n == 0)

return true;

return false;

}

//打印B树

public void print() {

int level = 0;

Deque> queue1 = new

ArrayDeque.BTNode>();

Deque> queue2 = new

ArrayDeque.BTNode>();

// 添加子节点

queue1.add(root);

while (!queue1.isEmpty() || !queue2.isEmpty()) {

//转移元素

if(queue1.isEmpty()){

level++;

while (!queue2.isEmpty()) {

queue1.add(queue2.poll());

}

}

System.out.format("Level_%d : ", level);

BTNodenode = queue1.poll();

for (int i = 0; i < node.n; i++) {

System.out.format("M",node.keys.get(i));

}

System.out.println();

//添加至下一层

if (!node.isLeaf) {

for (int i = 0; i < node.n + 1; i++) {

queue2.add(node.children.get(i));

}

}

}

}

public static void main(String[] args) {

MyBTree bTree = new MyBTree(20);

Random random = new Random();

for(int index = 0;index < 200;++index){

int temp = random.nextInt(128)+1;

bTree.insert(temp);

}

bTree.print();

System.out.println(bTree.size());

System.out.println(bTree.contains(77));

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BPlusTree_Java实现 package bplustree; import java.util.*; import com.xuedi.IO.*; import com.xuedi.maths.*; ////// DisposeRoot ///////中的key参数有些问题 public class BTree { //用于记录每个节点中的键值数量 public int keyAmount; //的根节点 public Node root; public BTree(int keyAmount) { this.keyAmount = keyAmount; this.root = new Node(keyAmount); } //在B中插入叶节点///////////////////////////////////////////////////////////// public void insert(long key,Object pointer) { //找到应该插入的节点 Node theNode = search(key,root); //在叶节点中找到空闲空间,有的话就把键放在那里 if( !isFull(theNode) ) { putKeyToNode(key,pointer,theNode); }else{ //如果在适当的叶节点没有空间,就把该叶节点分裂成两个,并正确分配键值 Node newNode = separateLeaf(key,pointer,theNode); //如果分裂的是根节点,就新建一个新的根节点将新建的节点作为他的字节点 if( isRoot(theNode) ) { DisposeRoot(theNode,newNode,newNode.keys[0]); }else{ //将新建立的节点的指针插入到上层节点 insertToInnerNode(theNode.parent,newNode,newNode.keys[0]); } } } //lowerNode是下级节点分离后新建立的那个节点/////////////////////////////////////// //upperNode是lowerNode的上层节点 private void insertToInnerNode(Node upperNode,Node lowerNode,long key) { //上层节点有空位就直接插入 if( !isFull(upperNode) ) { putKeyToNode(key,lowerNode,upperNode); //重置父节点指针 pointerRedirect(upperNode); return; }else{ //如果分裂的是根节点,就新建一个新的根节点将新建的节点作为他的子节点 Node newNode; if( isRoot(upperNode) ) { newNode = separateInnerNode(key,lowerNode,upperNode); Node newRoot = new Node(this.keyAmount); newRoot.pointer[0] = upperNode; newRoot.pointer[1] = newNode; upperNode.parent = newRoot; newNode.parent = newRoot; newRoot.keyAmount = 1; newRoot.keys[0] = key; root = newRoot; //重置父节点指针 pointerRedirect(upperNode); return; }else{ //上层非根节点没有空位进行分裂和插入操作 newNode = separateInnerNode(key,lowerNode,upperNode); //重置父节点指针 pointerRedirect(upperNode); //记录要向上插入的键值在源节点中的位置(该键值在separateInnerNode()被保留在srcNode中) int keyToUpperNodePosition = upperNode.keyAmount; //向上递归插入 insertToInnerNode(upperNode.parent,newNode,upperNode.keys[keyToUpperNodePosition]); //重置父节点指针 pointerRedirect(newNode); } } } //将对应的内部节点进行分裂并正确分配键值,返回新建的节点 private Node separateInnerNode(long key,Object pointer,Node srcNode) { Node newNode = new Node(this.keyAmount); //因为我在Node中预制了一个位置用于插入,而下面的函数(putKeyToLeaf())不进行越界检查 //所以可以将键-指针对先插入到元节点,然后再分别放到两个节点中 putKeyToNode(key,pointer,srcNode); //先前节点后来因该有(n+1)/2取上界个键-值针对 int ptrSaveAmount = (int)com.xuedi.maths.NumericalBound.getBound(0,(double)(this.keyAmount+1)/2); int keySaveAmount = (int)com.xuedi.maths.NumericalBound.getBound(0,(double)(this.keyAmount)/2); int keyMoveAmount = (int)com.xuedi.maths.NumericalBound.getBound(1,(double)(this.keyAmount)/2); //(n+1)/2取上界个指针和n/2取上界个键留在源节点中 //剩下的n+1)/2取下界个指n/2取下界个键留在源节点中 for (int k = ptrSaveAmount; k < srcNode.keyAmount; k++) { newNode.add(srcNode.keys[k], srcNode.pointer[k]); } newNode.pointer[newNode.keyAmount] = srcNode.pointer[srcNode.pointer.length-1]; srcNode.keyAmount = keySaveAmount; return newNode; } //将对应的叶节点进行分裂并正确分配键值,返回新建的节点/////////////////////////////// private Node separateLeaf(long key,Object pointer,Node srcNode) { Node newNode = new Node(this.keyAmount); //兄弟间的指针传递 newNode.pointer[this.keyAmount] = srcNode.pointer[this.keyAmount]; //因为我在Node中预制了一个位置用于插入,而下面的函数(putKeyToLeaf())不进行越界检查 //所以可以将键-指针对先插入到元节点,然后再分别放到两个节点中 putKeyToNode(key,pointer,srcNode); //先前节点后来因该有(n+1)/2取上界个键-值针对 int oldNodeSize = (int)com.xuedi.maths.NumericalBound.getBound(0,(double)(this.keyAmount+1)/2); for(int k = oldNodeSize; k <= this.keyAmount; k++) { newNode.add(srcNode.keys[k],srcNode.pointer[k]); } srcNode.keyAmount = oldNodeSize; //更改指针--让新节点成为就节点的右边的兄弟 srcNode.pointer[this.keyAmount] = newNode; return newNode; } //把键值放到叶节点中--这个函数不进行越界检查//////////////////////////////////////// private void putKeyToNode(long key,Object pointer,Node theNode) { int position = getInsertPosition(key,theNode); //进行搬迁动作--------叶节点的搬迁 if( isLeaf(theNode) ) { if(theNode.keyAmount <= position) { theNode.add(key,pointer); return; } else{ for (int j = theNode.keyAmount - 1; j >= position; j--) { theNode.keys[j + 1] = theNode.keys[j]; theNode.pointer[j + 1] = theNode.pointer[j]; } theNode.keys[position] = key; theNode.pointer[position] = pointer; } }else{ //内部节点的搬迁----有一定的插入策略: //指针的插入比数据的插入多出一位 for (int j = theNode.keyAmount - 1; j >= position; j--) { theNode.keys[j + 1] = theNode.keys[j]; theNode.pointer[j + 2] = theNode.pointer[j+1]; } theNode.keys[position] = key; theNode.pointer[position+1] = pointer; } //键值数量加1 theNode.keyAmount++; } //获得正确的插入位置 private int getInsertPosition(long key,Node node) { //将数据插入到相应的位置 int position = 0; for (int i = 0; i < node.keyAmount; i++) { if (node.keys[i] > key) break; position++; } return position; } //有用的辅助函数//////////////////////////////////////////////////////////////// //判断某个结点是否已经装满了 private boolean isFull(Node node) { if(node.keyAmount >= this.keyAmount) return true; else return false; } //判断某个节点是否是叶子结点 private boolean isLeaf(Node node) { //int i = 0; if(node.keyAmount == 0) return true; //如果向下的指针是Node型,则肯定不是叶子节点 if(node.pointer[0] instanceof Node) return false; return true; } private boolean isRoot(Node node) { if( node.equals(this.root) ) return true; return false; } //给内部节点中的自己点重新定向自己的父亲 private void pointerRedirect(Node node) { for(int i = 0; i <= node.keyAmount; i++) { ((Node)node.pointer[i]).parent = node; } } //新建一个新的根节点将新建的节点作为他的字节点 private void DisposeRoot(Node child1,Node child2,long key) { Node newRoot = new Node(this.keyAmount); newRoot.pointer[0] = child1; newRoot.pointer[1] = child2; newRoot.keyAmount = 1; newRoot.keys[0] = key; root = newRoot; //如果两个孩子是叶节点就让他们两个相连接 if( isLeaf(child1) ) { //兄弟间的指针传递 child2.pointer[this.keyAmount] = child1.pointer[this.keyAmount]; child1.pointer[this.keyAmount] = child2; } pointerRedirect(root); return; } /////////////////////////////////////////////////////////////////////////////// //用于寻找键值key所在的或key应该插入的节点 //key为键值,curNode为当前节点--一般从root节点开始 public Node search(long key,Node curNode) { if (isLeaf(curNode)) return curNode; for (int i = 0; i < this.keyAmount; i++) { if (key < curNode.keys[i]) //判断是否是第一个值 return search(key, (Node) curNode.pointer[i]); else if (key >= curNode.keys[i]) { if (i == curNode.keyAmount - 1) //如果后面没有值 { //如果key比最后一个键值大,则给出最后一个指针进行递归查询 return search(key,(Node) curNode.pointer[curNode.keyAmount]); } else { if (key < curNode.keys[i + 1]) return search(key, (Node) curNode.pointer[i + 1]); } } } //永远也不会到达这里 return null; } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值