B+樹的Java實現
阿新 • • 發佈:2018-12-23
下面的B+樹演算法是在我學習了別人的程式碼之後經過修改完成的,主要在葉子節點上使用了二分查詢,另外在更新節點上也減少了部分的遞迴操作,還對節點的結構做了細微的修改(每個節點得孩子指標比關鍵碼多1,原來是孩子指標和關鍵碼一樣多,這也與B+樹的原本定義一致),應該說整個程式的邏輯比原來清晰了一些。在此特別感謝wguoyong作者!大家可以參考原博主的程式碼點選開啟連結
在寫B+樹的過程中,其實查詢和插入操作都不算很難,最難的是刪除操作,在做中間節點合併的時候需要特別注意關鍵字和孩子指標的更新,具體見程式碼。
我對改進後的演算法與之前的做了比較,下面的測試我在Macbook air OS X 10.9.2上做的測試:
階數10階 |
修改前 |
修改後 |
隨機插入100萬條資料 |
4100ms |
2200ms |
順序插入100萬條資料 |
1800ms |
940ms |
隨機查詢100萬次資料 |
2800ms |
1350ms |
順序查詢100萬次資料 |
730ms |
250ms |
隨機刪除100萬次資料 |
4600ms |
1400ms |
順序刪除100萬次資料 |
2000ms |
450ms |
階數100階 |
修改前 |
修改後 |
隨機插入100萬條資料 |
8100ms |
2100ms |
順序插入100萬條資料 |
4300ms |
700ms |
隨機查詢100萬次資料 |
2000ms |
1200ms |
順序查詢100萬次資料 |
850ms |
250ms |
隨機刪除100萬次資料 |
8000ms |
1500ms |
順序刪除100萬次資料 |
4500ms |
300ms |
BplusTree.java
BplusNode.java/** * B+樹的定義: * * 1.任意非葉子結點最多有M個子節點;且M>2;M為B+樹的階數 * 2.除根結點以外的非葉子結點至少有 (M+1)/2個子節點; * 3.根結點至少有2個子節點; * 4.除根節點外每個結點存放至少(M-1)/2和至多M-1個關鍵字;(至少1個關鍵字) * 5.非葉子結點的子樹指標比關鍵字多1個; * 6.非葉子節點的所有key按升序存放,假設節點的關鍵字分別為K[0], K[1] … K[M-2], * 指向子女的指標分別為P[0], P[1]…P[M-1]。則有: * P[0] < K[0] <= P[1] < K[1] …..< K[M-2] <= P[M-1] * 7.所有葉子結點位於同一層; * 8.為所有葉子結點增加一個鏈指標; * 9.所有關鍵字都在葉子結點出現 */ /** * @author LeeJay 2014-04-03 * */ import java.util.ArrayList; import java.util.List; import java.util.Random; public class BplusTree <K extends Comparable<K>, V>{ /** 根節點 */ protected BplusNode<K, V> root; /** 階數,M值 */ protected int order; /** 葉子節點的連結串列頭 */ protected BplusNode<K, V> head; /** 樹高*/ protected int height = 0; public BplusNode<K, V> getHead() { return head; } public void setHead(BplusNode<K, V> head) { this.head = head; } public BplusNode<K, V> getRoot() { return root; } public void setRoot(BplusNode<K, V> root) { this.root = root; } public int getOrder() { return order; } public void setOrder(int order) { this.order = order; } public void setHeight(int height) { this.height = height; } public int getHeight() { return height; } public V get(K key) { return root.get(key); } public V remove(K key) { return root.remove(key, this); } public void insertOrUpdate(K key, V value) { root.insertOrUpdate(key, value, this); } public BplusTree(int order) { if (order < 3) { System.out.print("order must be greater than 2"); System.exit(0); } this.order = order; root = new BplusNode<K, V>(true, true); head = root; } // 測試 public static void main(String[] args) { int size = 1000000; int order = 100; // testRandomInsert(size, order); // // testOrderInsert(size, order); // // testRandomSearch(size, order); // // testOrderSearch(size, order); // // testRandomRemove(size, order); // // testOrderRemove(size, order); } private static void testOrderRemove(int size, int order) { BplusTree<Integer, Integer> tree = new BplusTree<Integer, Integer>(order); System.out.println("\nTest order remove " + size + " datas, of order:" + order); System.out.println("Begin order insert..."); for (int i = 0; i < size; i++) { tree.insertOrUpdate(i, i); } System.out.println("Begin order remove..."); long current = System.currentTimeMillis(); for (int j = 0; j < size; j++) { if (tree.remove(j) == null) { System.err.println("得不到資料:" + j); break; } } long duration = System.currentTimeMillis() - current; System.out.println("time elpsed for duration: " + duration); System.out.println(tree.getHeight()); } private static void testRandomRemove(int size, int order) { BplusTree<Integer, Integer> tree = new BplusTree<Integer, Integer>(order); System.out.println("\nTest random remove " + size + " datas, of order:" + order); Random random = new Random(); boolean[] a = new boolean[size + 10]; List<Integer> list = new ArrayList<Integer>(); int randomNumber = 0; System.out.println("Begin random insert..."); for (int i = 0; i < size; i++) { randomNumber = random.nextInt(size); a[randomNumber] = true; list.add(randomNumber); tree.insertOrUpdate(randomNumber, randomNumber); } System.out.println("Begin random remove..."); long current = System.currentTimeMillis(); for (int j = 0; j < size; j++) { randomNumber = list.get(j); if (a[randomNumber]) { if (tree.remove(randomNumber) == null) { System.err.println("得不到資料:" + randomNumber); break; } else { a[randomNumber] = false; } } } long duration = System.currentTimeMillis() - current; System.out.println("time elpsed for duration: " + duration); System.out.println(tree.getHeight()); } private static void testOrderSearch(int size, int order) { BplusTree<Integer, Integer> tree = new BplusTree<Integer, Integer>(order); System.out.println("\nTest order search " + size + " datas, of order:" + order); System.out.println("Begin order insert..."); for (int i = 0; i < size; i++) { tree.insertOrUpdate(i, i); } System.out.println("Begin order search..."); long current = System.currentTimeMillis(); for (int j = 0; j < size; j++) { if (tree.get(j) == null) { System.err.println("得不到資料:" + j); break; } } long duration = System.currentTimeMillis() - current; System.out.println("time elpsed for duration: " + duration); } private static void testRandomSearch(int size, int order) { BplusTree<Integer, Integer> tree = new BplusTree<Integer, Integer>(order); System.out.println("\nTest random search " + size + " datas, of order:" + order); Random random = new Random(); boolean[] a = new boolean[size + 10]; int randomNumber = 0; System.out.println("Begin random insert..."); for (int i = 0; i < size; i++) { randomNumber = random.nextInt(size); a[randomNumber] = true; tree.insertOrUpdate(randomNumber, randomNumber); } System.out.println("Begin random search..."); long current = System.currentTimeMillis(); for (int j = 0; j < size; j++) { randomNumber = random.nextInt(size); if (a[randomNumber]) { if (tree.get(randomNumber) == null) { System.err.println("得不到資料:" + randomNumber); break; } } } long duration = System.currentTimeMillis() - current; System.out.println("time elpsed for duration: " + duration); } private static void testRandomInsert(int size, int order) { BplusTree<Integer, Integer> tree = new BplusTree<Integer, Integer>(order); System.out.println("\nTest random insert " + size + " datas, of order:" + order); Random random = new Random(); int randomNumber = 0; long current = System.currentTimeMillis(); for (int i = 0; i < size; i++) { randomNumber = random.nextInt(size); tree.insertOrUpdate(randomNumber, randomNumber); } long duration = System.currentTimeMillis() - current; System.out.println("time elpsed for duration: " + duration); System.out.println(tree.getHeight()); } private static void testOrderInsert(int size, int order) { BplusTree<Integer, Integer> tree = new BplusTree<Integer, Integer>(order); System.out.println("\nTest order insert " + size + " datas, of order:" + order); long current = System.currentTimeMillis(); for (int i = 0; i < size; i++) { tree.insertOrUpdate(i, i); } long duration = System.currentTimeMillis() - current; System.out.println("time elpsed for duration: " + duration); } }
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
public class BplusNode <K extends Comparable<K>, V> {
/** 是否為葉子節點 */
protected boolean isLeaf;
/** 是否為根節點*/
protected boolean isRoot;
/** 父節點 */
protected BplusNode<K, V> parent;
/** 葉節點的前節點*/
protected BplusNode<K, V> previous;
/** 葉節點的後節點*/
protected BplusNode<K, V> next;
/** 節點的關鍵字 */
protected List<Entry<K, V>> entries;
/** 子節點 */
protected List<BplusNode<K, V>> children;
public BplusNode(boolean isLeaf) {
this.isLeaf = isLeaf;
entries = new ArrayList<Entry<K, V>>();
if (!isLeaf) {
children = new ArrayList<BplusNode<K, V>>();
}
}
public BplusNode(boolean isLeaf, boolean isRoot) {
this(isLeaf);
this.isRoot = isRoot;
}
public V get(K key) {
//如果是葉子節點
if (isLeaf) {
int low = 0, high = entries.size() - 1, mid;
int comp ;
while (low <= high) {
mid = (low + high) / 2;
comp = entries.get(mid).getKey().compareTo(key);
if (comp == 0) {
return entries.get(mid).getValue();
} else if (comp < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
//未找到所要查詢的物件
return null;
}
//如果不是葉子節點
//如果key小於節點最左邊的key,沿第一個子節點繼續搜尋
if (key.compareTo(entries.get(0).getKey()) < 0) {
return children.get(0).get(key);
//如果key大於等於節點最右邊的key,沿最後一個子節點繼續搜尋
}else if (key.compareTo(entries.get(entries.size()-1).getKey()) >= 0) {
return children.get(children.size()-1).get(key);
//否則沿比key大的前一個子節點繼續搜尋
}else {
int low = 0, high = entries.size() - 1, mid= 0;
int comp ;
while (low <= high) {
mid = (low + high) / 2;
comp = entries.get(mid).getKey().compareTo(key);
if (comp == 0) {
return children.get(mid+1).get(key);
} else if (comp < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return children.get(low).get(key);
}
}
public void insertOrUpdate(K key, V value, BplusTree<K,V> tree){
//如果是葉子節點
if (isLeaf){
//不需要分裂,直接插入或更新
if (contains(key) != -1 || entries.size() < tree.getOrder()){
insertOrUpdate(key, value);
if(tree.getHeight() == 0){
tree.setHeight(1);
}
return ;
}
//需要分裂
//分裂成左右兩個節點
BplusNode<K,V> left = new BplusNode<K,V>(true);
BplusNode<K,V> right = new BplusNode<K,V>(true);
//設定連結
if (previous != null){
previous.next = left;
left.previous = previous ;
}
if (next != null) {
next.previous = right;
right.next = next;
}
if (previous == null){
tree.setHead(left);
}
left.next = right;
right.previous = left;
previous = null;
next = null;
//複製原節點關鍵字到分裂出來的新節點
copy2Nodes(key, value, left, right, tree);
//如果不是根節點
if (parent != null) {
//調整父子節點關係
int index = parent.children.indexOf(this);
parent.children.remove(this);
left.parent = parent;
right.parent = parent;
parent.children.add(index,left);
parent.children.add(index + 1, right);
parent.entries.add(index,right.entries.get(0));
entries = null; //刪除當前節點的關鍵字資訊
children = null; //刪除當前節點的孩子節點引用
//父節點插入或更新關鍵字
parent.updateInsert(tree);
parent = null; //刪除當前節點的父節點引用
//如果是根節點
}else {
isRoot = false;
BplusNode<K,V> parent = new BplusNode<K,V> (false, true);
tree.setRoot(parent);
left.parent = parent;
right.parent = parent;
parent.children.add(left);
parent.children.add(right);
parent.entries.add(right.entries.get(0));
entries = null;
children = null;
}
return ;
}
//如果不是葉子節點
//如果key小於等於節點最左邊的key,沿第一個子節點繼續搜尋
if (key.compareTo(entries.get(0).getKey()) < 0) {
children.get(0).insertOrUpdate(key, value, tree);
//如果key大於節點最右邊的key,沿最後一個子節點繼續搜尋
}else if (key.compareTo(entries.get(entries.size()-1).getKey()) >= 0) {
children.get(children.size()-1).insertOrUpdate(key, value, tree);
//否則沿比key大的前一個子節點繼續搜尋
}else {
int low = 0, high = entries.size() - 1, mid= 0;
int comp ;
while (low <= high) {
mid = (low + high) / 2;
comp = entries.get(mid).getKey().compareTo(key);
if (comp == 0) {
children.get(mid+1).insertOrUpdate(key, value, tree);
break;
} else if (comp < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
if(low>high){
children.get(low).insertOrUpdate(key, value, tree);
}
}
}
private void copy2Nodes(K key, V value, BplusNode<K,V> left,
BplusNode<K,V> right,BplusTree<K,V> tree) {
//左右兩個節點關鍵字長度
int leftSize = (tree.getOrder() + 1) / 2 + (tree.getOrder() + 1) % 2;
boolean b = false;//用於記錄新元素是否已經被插入
for (int i = 0; i < entries.size(); i++) {
if(leftSize !=0){
leftSize --;
if(!b&&entries.get(i).getKey().compareTo(key) > 0){
left.entries.add(new SimpleEntry<K, V>(key, value));
b = true;
i--;
}else {
left.entries.add(entries.get(i));
}
}else {
if(!b&&entries.get(i).getKey().compareTo(key) > 0){
right.entries.add(new SimpleEntry<K, V>(key, value));
b = true;
i--;
}else {
right.entries.add(entries.get(i));
}
}
}
if(!b){
right.entries.add(new SimpleEntry<K, V>(key, value));
}
}
/** 插入節點後中間節點的更新 */
protected void updateInsert(BplusTree<K,V> tree){
//如果子節點數超出階數,則需要分裂該節點
if (children.size() > tree.getOrder()) {
//分裂成左右兩個節點
BplusNode<K, V> left = new BplusNode<K, V>(false);
BplusNode<K, V> right = new BplusNode<K, V>(false);
//左右兩個節點子節點的長度
int leftSize = (tree.getOrder() + 1) / 2 + (tree.getOrder() + 1) % 2;
int rightSize = (tree.getOrder() + 1) / 2;
//複製子節點到分裂出來的新節點,並更新關鍵字
for (int i = 0; i < leftSize; i++){
left.children.add(children.get(i));
children.get(i).parent = left;
}
for (int i = 0; i < rightSize; i++){
right.children.add(children.get(leftSize + i));
children.get(leftSize + i).parent = right;
}
for (int i = 0; i < leftSize - 1; i++) {
left.entries.add(entries.get(i));
}
for (int i = 0; i < rightSize - 1; i++) {
right.entries.add(entries.get(leftSize + i));
}
//如果不是根節點
if (parent != null) {
//調整父子節點關係
int index = parent.children.indexOf(this);
parent.children.remove(this);
left.parent = parent;
right.parent = parent;
parent.children.add(index,left);
parent.children.add(index + 1, right);
parent.entries.add(index,entries.get(leftSize - 1));
entries = null;
children = null;
//父節點更新關鍵字
parent.updateInsert(tree);
parent = null;
//如果是根節點
}else {
isRoot = false;
BplusNode<K, V> parent = new BplusNode<K, V>(false, true);
tree.setRoot(parent);
tree.setHeight(tree.getHeight() + 1);
left.parent = parent;
right.parent = parent;
parent.children.add(left);
parent.children.add(right);
parent.entries.add(entries.get(leftSize - 1));
entries = null;
children = null;
}
}
}
/** 刪除節點後中間節點的更新*/
protected void updateRemove(BplusTree<K,V> tree) {
// 如果子節點數小於M / 2或者小於2,則需要合併節點
if (children.size() < tree.getOrder() / 2 || children.size() < 2) {
if (isRoot) {
// 如果是根節點並且子節點數大於等於2,OK
if (children.size() >= 2) return;
// 否則與子節點合併
BplusNode<K, V> root = children.get(0);
tree.setRoot(root);
tree.setHeight(tree.getHeight() - 1);
root.parent = null;
root.isRoot = true;
entries = null;
children = null;
return ;
}
//計算前後節點
int currIdx = parent.children.indexOf(this);
int prevIdx = currIdx - 1;
int nextIdx = currIdx + 1;
BplusNode<K, V> previous = null, next = null;
if (prevIdx >= 0) {
previous = parent.children.get(prevIdx);
}
if (nextIdx < parent.children.size()) {
next = parent.children.get(nextIdx);
}
// 如果前節點子節點數大於M / 2並且大於2,則從其處借補
if (previous != null
&& previous.children.size() > tree.getOrder() / 2
&& previous.children.size() > 2) {
//前葉子節點末尾節點新增到首位
int idx = previous.children.size() - 1;
BplusNode<K, V> borrow = previous.children.get(idx);
previous.children.remove(idx);
borrow.parent = this;
children.add(0, borrow);
int preIndex = parent.children.indexOf(previous);
entries.add(0,parent.entries.get(preIndex));
parent.entries.set(preIndex, previous.entries.remove(idx - 1));
return ;
}
// 如果後節點子節點數大於M / 2並且大於2,則從其處借補
if (next != null
&& next.children.size() > tree.getOrder() / 2
&& next.children.size() > 2) {
//後葉子節點首位新增到末尾
BplusNode<K, V> borrow = next.children.get(0);
next.children.remove(0);
borrow.parent = this;
children.add(borrow);
int preIndex = parent.children.indexOf(this);
entries.add(parent.entries.get(preIndex));
parent.entries.set(preIndex, next.entries.remove(0));
return ;
}
// 同前面節點合併
if (previous != null
&& (previous.children.size() <= tree.getOrder() / 2
|| previous.children.size() <= 2)) {
for (int i = 0; i < children.size(); i++) {
previous.children.add(children.get(i));
}
for(int i = 0; i < previous.children.size();i++){
previous.children.get(i).parent = this;
}
int indexPre = parent.children.indexOf(previous);
previous.entries.add(parent.entries.get(indexPre));
for (int i = 0; i < entries.size(); i++) {
previous.entries.add(entries.get(i));
}
children = previous.children;
entries = previous.entries;
//更新父節點的關鍵字列表
parent.children.remove(previous);
previous.parent = null;
previous.children = null;
previous.entries = null;
parent.entries.remove(parent.children.indexOf(this));
if((!parent.isRoot
&& (parent.children.size() >= tree.getOrder() / 2
&& parent.children.size() >= 2))
||parent.isRoot && parent.children.size() >= 2){
return ;
}
parent.updateRemove(tree);
return ;
}
// 同後面節點合併
if (next != null
&& (next.children.size() <= tree.getOrder() / 2
|| next.children.size() <= 2)) {
for (int i = 0; i < next.children.size(); i++) {
BplusNode<K, V> child = next.children.get(i);
children.add(child);
child.parent = this;
}
int index = parent.children.indexOf(this);
entries.add(parent.entries.get(index));
for (int i = 0; i < next.entries.size(); i++) {
entries.add(next.entries.get(i));
}
parent.children.remove(next);
next.parent = null;
next.children = null;
next.entries = null;
parent.entries.remove(parent.children.indexOf(this));
if((!parent.isRoot && (parent.children.size() >= tree.getOrder() / 2
&& parent.children.size() >= 2))
||parent.isRoot && parent.children.size() >= 2){
return ;
}
parent.updateRemove(tree);
return ;
}
}
}
public V remove(K key, BplusTree<K,V> tree){
//如果是葉子節點
if (isLeaf){
//如果不包含該關鍵字,則直接返回
if (contains(key) == -1){
return null;
}
//如果既是葉子節點又是根節點,直接刪除
if (isRoot) {
if(entries.size() == 1){
tree.setHeight(0);
}
return remove(key);
}
//如果關鍵字數大於M / 2,直接刪除
if (entries.size() > tree.getOrder() / 2 && entries.size() > 2) {
return remove(key);
}
//如果自身關鍵字數小於M / 2,並且前節點關鍵字數大於M / 2,則從其處借補
if (previous != null &&
previous.parent == parent
&& previous.entries.size() > tree.getOrder() / 2
&& previous.entries.size() > 2 ) {
//新增到首位
int size = previous.entries.size();
entries.add(0, previous.entries.remove(size - 1));
int index = parent.children.indexOf(previous);
parent.entries.set(index, entries.get(0));
return remove(key);
}
//如果自身關鍵字數小於M / 2,並且後節點關鍵字數大於M / 2,則從其處借補
if (next != null
&& next.parent == parent
&& next.entries.size() > tree.getOrder() / 2
&& next.entries.size() > 2) {
entries.add(next.entries.remove(0));
int index = parent.children.indexOf(this);
parent.entries.set(index, next.entries.get(0));
return remove(key);
}
//同前面節點合併
if (previous != null
&& previous.parent == parent
&& (previous.entries.size() <= tree.getOrder() / 2
|| previous.entries.size() <= 2)) {
V returnValue = remove(key);
for (int i = 0; i < entries.size(); i++) {
//將當前節點的關鍵字新增到前節點的末尾
previous.entries.add(entries.get(i));
}
entries = previous.entries;
parent.children.remove(previous);
previous.parent = null;
previous.entries = null;
//更新連結串列
if (previous.previous != null) {
BplusNode<K, V> temp = previous;
temp.previous.next = this;
previous = temp.previous;
temp.previous = null;
temp.next = null;
}else {
tree.setHead(this);
previous.next = null;
previous = null;
}
parent.entries.remove(parent.children.indexOf(this));
if((!parent.isRoot && (parent.children.size() >= tree.getOrder() / 2
&& parent.children.size() >= 2))
||parent.isRoot && parent.children.size() >= 2){
return returnValue;
}
parent.updateRemove(tree);
return returnValue;
}
//同後面節點合併
if(next != null
&& next.parent == parent
&& (next.entries.size() <= tree.getOrder() / 2
|| next.entries.size() <= 2)) {
V returnValue = remove(key);
for (int i = 0; i < next.entries.size(); i++) {
//從首位開始新增到末尾
entries.add(next.entries.get(i));
}
next.parent = null;
next.entries = null;
parent.children.remove(next);
//更新連結串列
if (next.next != null) {
BplusNode<K, V> temp = next;
temp.next.previous = this;
next = temp.next;
temp.previous = null;
temp.next = null;
}else {
next.previous = null;
next = null;
}
//更新父節點的關鍵字列表
parent.entries.remove(parent.children.indexOf(this));
if((!parent.isRoot && (parent.children.size() >= tree.getOrder() / 2
&& parent.children.size() >= 2))
||parent.isRoot && parent.children.size() >= 2){
return returnValue;
}
parent.updateRemove(tree);
return returnValue;
}
}
/*如果不是葉子節點*/
//如果key小於等於節點最左邊的key,沿第一個子節點繼續搜尋
if (key.compareTo(entries.get(0).getKey()) < 0) {
return children.get(0).remove(key, tree);
//如果key大於節點最右邊的key,沿最後一個子節點繼續搜尋
}else if (key.compareTo(entries.get(entries.size()-1).getKey()) >= 0) {
return children.get(children.size()-1).remove(key, tree);
//否則沿比key大的前一個子節點繼續搜尋
}else {
int low = 0, high = entries.size() - 1, mid= 0;
int comp ;
while (low <= high) {
mid = (low + high) / 2;
comp = entries.get(mid).getKey().compareTo(key);
if (comp == 0) {
return children.get(mid + 1).remove(key, tree);
} else if (comp < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return children.get(low).remove(key, tree);
}
}
/** 判斷當前節點是否包含該關鍵字*/
protected int contains(K key) {
int low = 0, high = entries.size() - 1, mid;
int comp ;
while (low <= high) {
mid = (low + high) / 2;
comp = entries.get(mid).getKey().compareTo(key);
if (comp == 0) {
return mid;
} else if (comp < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
/** 插入到當前節點的關鍵字中*/
protected void insertOrUpdate(K key, V value){
//二叉查詢,插入
int low = 0, high = entries.size() - 1, mid;
int comp ;
while (low <= high) {
mid = (low + high) / 2;
comp = entries.get(mid).getKey().compareTo(key);
if (comp == 0) {
entries.get(mid).setValue(value);
break;
} else if (comp < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
if(low>high){
entries.add(low, new SimpleEntry<K, V>(key, value));
}
}
/** 刪除節點*/
protected V remove(K key){
int low = 0,high = entries.size() -1,mid;
int comp;
while(low<= high){
mid = (low+high)/2;
comp = entries.get(mid).getKey().compareTo(key);
if(comp == 0){
return entries.remove(mid).getValue();
}else if(comp < 0){
low = mid + 1;
}else {
high = mid - 1;
}
}
return null;
}
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("isRoot: ");
sb.append(isRoot);
sb.append(", ");
sb.append("isLeaf: ");
sb.append(isLeaf);
sb.append(", ");
sb.append("keys: ");
for (Entry<K,V> entry : entries){
sb.append(entry.getKey());
sb.append(", ");
}
sb.append(", ");
return sb.toString();
}
}