我正在尝试实施 B树的insert
操作。
以下是node
的实现:
import java.util.ArrayList;
import java.util.List;
/**
* Represent a node in a B Tree. The keys in a node have to be sortable.
*/
public class BTreeNode<K extends Comparable<K>, V> {
/**
* Array of keys (or key-value-pairs) in the node.
*/
private List<KeyValuePair<K, V>> keyValPair = new ArrayList<>();
/**
* Array of references to child nodes.
*/
private List<BTreeNode<K, V>> child;
/**
* parent node, null in case of root node
*/
private BTreeNode<K, V> parent = null;
/**
* Construct a B-tree node initially with one element and two children.
* @param element a key-value-pair
*/
public BTreeNode(KeyValuePair<K, V> element) {
keyValPair = new ArrayList<KeyValuePair<K, V>>();
keyValPair.add(element);
// 2 children
child = new ArrayList<>();
child.add(null);
child.add(null);
}
/**
* Check if a node is leaf node.
* @return false, when the node has at least a non-null child, or else true
*/
public boolean isLeaf() {
for (BTreeNode<K, V> child : child) {
if (child != null) {
return false;
}
}
return true;
}
/**
* Get number of keys in the node.
*/
public int size() {
return keyValPair.size();
}
/**
* Get number of children.
*/
public int numOfChilds() {
return child.size();
}
/**
* Extract from current node the pairs that have index within left..(right-1)
* and children index within left..right
*
* @param left index lower bound
* @param right index strict upper bound
* @return subnode
*/
public BTreeNode<K, V> subNode(int left, int right) {
BTreeNode<K, V> res = new BTreeNode<>(null);
for (int i = left; i < right; i++) {
res.addKeyValPair(i - left, getKeyValPair(i));
res.setChild(i - left, getChild(i));
}
res.setChild(right - left, getChild(right));
return res;
}
/**
* Insert an element (a key-value-pair) at a given index (before the key that was at that position).
* Insert automatically a null child.
*/
public void addKeyValPair(int index, KeyValuePair<K, V> element) {
if (keyValPair.size() == 0) {
child.add(null);
}
keyValPair.add(index, element);
child.add(index, null);
}
/**
* Get the key at a given position.
*/
public KeyValuePair<K, V> getKeyValPair(int index) {
return keyValPair.get(index);
}
/**
* Get the parent node.
*/
public BTreeNode<K, V> getParent() {
return parent;
}
/**
* Get a child node at a given position.
*/
public BTreeNode<K, V> getChild(int index) {
return child.get(index);
}
/**
* Insert a new element, set 2 nodes as its children.
*/
public void insertKeyChild(BTreeNode<K, V> leftNode, KeyValuePair<K, V> element,
BTreeNode<K, V> rightNode) {
// Finde index des Teiler
int index = -1;
if (element.getKey().compareTo(getKeyValPair(0).getKey()) < 0) {
index = 0;
} else if (element.getKey().compareTo(getKeyValPair(size() - 1).getKey()) > 0) {
element = size() - 1;
} else {
for (int i = 0; i < size() - 1; i++) {
if (element.getKey().compareTo(getKeyValPair(i + 1).getKey()) < 0) {
index = i + 1;
break;
}
}
}
addKeyValPair(index, element);
setChild(index, leftNode);
setChild(index + 1, rightNode);
}
/**
* Replace a child node at given position. Index has to be available.
*/
public void setChild(int index, BTreeNode<K, V> node) {
child.set(index, node);
if (node != null) {
node.setParent(this);
}
}
/**
* Set a node as parent node
*/
public void setParent(BTreeNode<K, V> node) {
parent = node;
}
/**
* Find the position of a key (to put) in a node
*
* @param target a key that needs to be search
* @return the index of the leftmost element in this node that is not less than target.
*/
public int searchInNode(KeyValuePair<K, V> target) {
int l = 0;
int r = size() - 1;
while (l <= r) {
int m = (l + r) / 2;
int comp = target.getKey().compareTo(getKeyValPair(m).getKey());
if (comp == 0)
return m;
else if (comp < 0)
r = m - 1;
else
l = m + 1;
}
return l;
}
@Override
public String toString() {
String ergebnis = "(" + ((getChild(0) != null) ? " " + getChild(0) + " " : "") + ")";
for (int i = 0; i < keyValPair.size(); i++) {
ergebnis += getKeyValPair(i).getKey() + ""; // NullPointerException
ergebnis += "(" + ((getChild(i + 1) != null) ? " " + getChild(i + 1) + " " : "") + ")";
}
ergebnis += "";
return ergebnis;
}
}
这是我对B Tree的实现:
import java.util.ArrayList;
import java.util.List;
public abstract class BTree<K extends Comparable<K>, V> {
/**
* root node
*/
protected BTreeKnoten<K, V> root = null;
/**
* Order (degree) of the tree
*/
protected int deg;
public BTree(int deg) {
this.deg = deg;
}
/**
* maximum number of key-value-pairs in a node
*/
public int maxNodeSize() {
return 2 * deg - 2;
}
@Override
public String toString() {
return root.toString();
}
/**
* Get the value from a key in the tree. Give null if the key is not found.
* @param key
*/
public V getValFromKey(K key) {
if (root == null) {
return null;
}
return getValFromKey(key, root);
}
/**
* Get the value from a key in a subtree. Give null if the key is not found.
* @param key
* @param node root node of the subtree
*/
private V getValFromKey(K key, BTreeNode<K, V> node) {
if (node == null) {
return null;
}
for (int i = 0; i < node.size(); i++) {
KeyValuePair<K, V> key_val = node.getKeyValPair(i);
if (key_val.getKey().compareTo(key) == 0) {
return key_val.getValue();
} else if (key_val.getKey().compareTo(key) > 0) {
return getValFromKey(key, node.getChild(i));
}
}
return getValFromKey(key, node.getChild(node.numOfChilds() - 1));
}
/**
* Get number of keys in the tree.
*/
public int numOfKeys() {
return numOfKeys(root);
}
/**
* Get number of keys in a subtree
* @param node root of subtree
*/
private int numOfKeys(BTreeKnoten<K, V> node) {
if (node == null) {
return 0;
}
int res = node.size();
for (int i = 0; i < node.numOfChilds(); i++) {
res += numOfKeys(node.getChild(i));
}
return res;
}
/**
* Insert a new element (key+value) into the tree.
* @param key
* @param value
* @return new root node of the tree
*/
public BTreeNode<K, V> insert(K key, V value) {
KeyValuePair<K, V> insertPair = new KeyValuePair<K, V>(key, value);
// if tree is empty, simply insert new
if (root == null) {
root = new BTreeKnoten<>(insertPair);
return root;
}
BTreeNode<K, V> curr = root;
for (;;) {
// position of insertPair in current node
int currPos = curr.searchInNode(insertPair);
// if position of insertion is in a leaf -> insert
if (curr.isLeaf()) {
curr.addKeyValPair(currPos, insertPair);
// if current node becomes overflowed
if (curr.size() > maxNodeSize()) {
splitNode(curr);
}
return root;
} else {
// traverse down to a child (until reaching a leaf)
curr = curr.getChild(currPos);
}
}
}
/**
* Split the current node, push the middle element into its parent node
* @param node
*/
public void splitNode(BTreeKnoten<K, V> node) {
// seperate current node into 3 parts
int medPos = node.size() / 2;
KeyValuePair<K, V> med = node.getKeyValPair(medPos);
BTreeKnoten<K, V> leftSubNode = node.subNode(0, medPos);
BTreeKnoten<K, V> rightSubNode = node.subNode(medPos + 1, node.size());
// if root node is to be split
if (node == root) {
// set med as new root
root = new BTreeKnoten<>(med);
// set leftSubNode and rightSubNode as its two children
root.setChild(0, leftSubNode);
root.setChild(1, rightSubNode);
} else {
BTreeNode<K, V> parent = node.getParent();
// push med into parent and make leftSubNode and rightSubNode its children
parent.insertKeyChild(leftSubNode, med, rightSubNode);
// if parent becomes overflowed, split again
if (parent.size() > maxNodeSize()) {
splitNode(parent);
}
}
}
public static void main(String[] args) {
BTree<Integer, String> baum = new BTree<Integer, String>(2) {
};
baum.insert(23, "23");
System.out.println(baum);
System.out.println(baum.numOfKeys()); // 1
baum.insert(42, "42");
System.out.println(baum);
System.out.println(baum.numOfKeys()); // 2
baum.insert(12, "12");
System.out.println(baum);
System.out.println(baum.numOfKeys()); // 5 (?!)
}
}
当我尝试insert 12
进入树{NullPointerException
toString()
BTreeNode
)时,程序会出现错误。
那时我们应该split
节点。
numOfKeys()
时insert 12
的结果也是假的。所以我的猜测是splitNode()
可能存在一些问题,使程序对密钥和子项的数量感到困惑。
我找不到确切的问题所在。有人可以帮帮我吗?