deletion btree rest

This commit is contained in:
Wouter Groeneveld 2018-04-04 17:21:44 +02:00
parent 01368089b1
commit 959e23575d
4 changed files with 188 additions and 23 deletions

View File

@ -1,5 +1,8 @@
package be.brainbaking.datastructures.trees;
import java.util.List;
import java.util.Optional;
public class BTree {
private Node root;
@ -53,26 +56,80 @@ public class BTree {
BTreeSearchResult searchResult = search(key);
if(!searchResult.isFound()) return;
Node node = searchResult.getNode();
Node parent = searchResult.getParent();
if(node.isLeaf() && node.getNumberOfKeys() >= t) { // case 1
node.deleteKey(key);
} else if(node.isLeaf() && node.getNumberOfKeys() == t - 1) { // case 3
if(searchResult.getParent().getSiblingsOf(node).stream().anyMatch(s -> s.getNumberOfKeys() == t)) {
List<Node> siblings = parent.getSiblingsOf(node);
Optional<Node> maybeSibling = getSiblingWithTNumberOfKeys(siblings);
if(maybeSibling.isPresent()) {
// 3.a
} else if(searchResult.getParent().getSiblingsOf(node).stream().allMatch(s -> s.getNumberOfKeys() == t - 1)) {
String parentKeyToPushDown = parent.getKeyBetweenChildren(node, maybeSibling.get());
String extremeKeyToPushUp = maybeSibling.get().getExtremeKeyComparedTo(parentKeyToPushDown);
pushKeyDown(node, parent, parentKeyToPushDown);
pullKeyUp(parent, maybeSibling, extremeKeyToPushUp);
node.deleteKey(key);
} else if(siblings.stream().allMatch(s -> s.getNumberOfKeys() == t - 1)) {
// 3.b
Node rightMostSibling = siblings.stream().filter(s -> s.getNumberOfKeys() == t - 1).reduce((one, two) -> two).get();
node.mergeWith(rightMostSibling);
String parentKeyToPushDown = parent.getKeyBetweenChildren(node, rightMostSibling);
parent.getChildren().remove(rightMostSibling);
pushKeyDown(node, parent, parentKeyToPushDown);
node.deleteKey(key);
}
} else if(!node.isLeaf()) { // case 2
if(node.getLeftChild().getNumberOfKeys() >= t) {
List<Node> children = node.getChildenBetweenKey(key);
Node left = children.get(0);
Node right = children.get(1);
if(left.getNumberOfKeys() >= t) {
// 2.a
} else if(node.getRightChild().getNumberOfKeys() >= t) {
switchKeys(node, key, left, left.getLastKey());
left.deleteKey(key);
} else if(right.getNumberOfKeys() >= t) {
// 2.b
switchKeys(node, key, right, right.getFirstKey());
right.deleteKey(key);
} else {
// 2.c
left.mergeWith(right);
node.getChildren().remove(right);
node.deleteKey(key);
}
}
}
private void switchKeys(Node node, String key, Node nodeToSwitch, String keyToSwith) {
node.getKeys().remove(key);
node.addKey(keyToSwith);
nodeToSwitch.getKeys().remove(keyToSwith);
nodeToSwitch.addKey(key);
}
private void pullKeyUp(Node parent, Optional<Node> maybeSibling, String extremeKeyToPushUp) {
maybeSibling.get().getKeys().remove(extremeKeyToPushUp);
parent.addKey(extremeKeyToPushUp);
}
private void pushKeyDown(Node node, Node parent, String parentKeyToPushDown) {
parent.getKeys().remove(parentKeyToPushDown);
node.addKey(parentKeyToPushDown);
}
private Optional<Node> getSiblingWithTNumberOfKeys(List<Node> siblings) {
return siblings.stream().filter(s -> s.getNumberOfKeys() == t).findFirst();
}
private void insertNonFull(Node node, String key) {
if(node.isLeaf()) {
node.addKey(key);

View File

@ -1,7 +1,10 @@
package be.brainbaking.datastructures.trees;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Each node has the following fields:
@ -35,6 +38,12 @@ public class Node {
this.leaf = leaf;
}
/**
* Voegt key gesorteerd toe.
* Dit heb ik enkel voor bepaalde gevallen nodig, maar gebruik ik hier gegeneraliseerd.
* Betekent een performance hit van worst-case O(n[x]) (bvb switchkeys) -> uit context af te leiden waar
* @param key
*/
public void addKey(String key) {
int i;
for(i = 0; i < keys.size(); i++) {
@ -46,27 +55,50 @@ public class Node {
keys.add(i, key);
}
public String getKey(Node child) {
for(int i = 0; i < keys.size(); i++) {
if(keys.get(i).compareTo(child.getKeys().get(0)) >= 0) {
public List<Node> getChildenBetweenKey(String key) {
int keyIndex = keys.indexOf(key);
return Arrays.asList(children.get(keyIndex), children.get(keyIndex + 1)); // kan volgens specs niet crashen, zie def. BTree props
}
public String getKeyBetweenChildren(Node child1, Node child2) {
return keys.get(Math.max(children.indexOf(child1), children.indexOf(child2)) - 1);
}
}
public String getExtremeKeyComparedTo(String parentKey) {
return parentKey.compareTo(keys.get(0)) < 0 ? keys.get(0) : keys.get(keys.size() - 1);
}
public List<Node> getSiblingsOf(Node child) {
List<Node> siblings = new ArrayList<>();
int index = children.indexOf(child);
if(index < children.size() - 1) {
siblings.add(children.get(index + 1));
}
if(index > 0) {
siblings.add(children.get(index - 1));
}
if(index < children.size() - 1) {
siblings.add(children.get(index + 1));
}
return siblings;
}
public void mergeWith(Node node) {
if(node.getKeys().get(0).compareTo(getKeys().get(0)) >= 0) {
rightSideMergeWith(node);
} else {
leftSideMergeWith(node);
}
}
private void leftSideMergeWith(Node node) {
keys = Stream.concat(node.keys.stream(), keys.stream()).collect(Collectors.toList());
children = Stream.concat(node.children.stream(), children.stream()).collect(Collectors.toList());
}
private void rightSideMergeWith(Node node) {
keys = Stream.concat(keys.stream(), node.keys.stream()).collect(Collectors.toList());
children = Stream.concat(children.stream(), node.children.stream()).collect(Collectors.toList());
}
public void addChild(Node node) {
addChild(children.size(), node);
}
@ -85,7 +117,7 @@ public class Node {
for(int i = 0; i < t - 1; i++) {
newNode.addKey(keys.get(i + t));
}
// ?? Aantal sleutels en aantal children kan niet gelijk zijn?
// n[x] = aantal sleutels = size(c[x]) - 1; er zijn altijd n[x] + 1 kinderen
if(!isLeaf()) {
for(int i = 0; i < t; i++) {
newNode.children.add(children.get(i + t - 1));
@ -123,18 +155,18 @@ public class Node {
return children;
}
public String getLastKey() {
return keys.get(getNumberOfKeys() - 1);
}
public String getFirstKey() {
return keys.get(0);
}
public List<String> getKeys() {
return keys;
}
public Node getLeftChild() {
return children.get(0);
}
public Node getRightChild() {
return children.get(children.size() - 1);
}
public boolean isLeaf() {
return leaf;
}

View File

@ -36,7 +36,7 @@ public class BTreeTest {
BTree tree = new BTree(root, 3);
tree.delete("B");
assertArrayEquals(Arrays.asList("A", "B").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
assertArrayEquals(Arrays.asList("A", "C").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
}
@Test

View File

@ -10,6 +10,82 @@ import static org.junit.jupiter.api.Assertions.assertSame;
public class NodeTest {
@Test
public void merge_addsKeysAndChildren() {
Node child = new Node(true);
child.addKey("I");
Node node = new Node(false);
node.addKey("G");
node.addKey("H");
node.addChild(new Node(true));
Node siblingToMergeWith = new Node(false);
siblingToMergeWith.addKey("K");
siblingToMergeWith.addKey("L");
Node siblingChild = new Node(true);
siblingChild.addKey("X");
siblingToMergeWith.addChild(siblingChild);
node.mergeWith(siblingToMergeWith);
assertArrayEquals(Arrays.asList("G", "H", "K", "L").toArray(), node.getKeys().toArray());
assertEquals(2, node.getChildren().size());
}
@Test
public void getKeyBetweenChildren_basedOnChildIndex() {
Node parent = new Node(false);
parent.addKey("J");
parent.addKey("M");
Node child1 = new Node(true);
child1.addKey("G");
child1.addKey("H");
parent.addChild(child1);
Node child2 = new Node(true);
child2.addKey("K");
child2.addKey("L");
parent.addChild(child2);
Node child3 = new Node(true);
child3.addKey("O");
child3.addKey("P");
child3.addKey("R");
parent.addChild(child3);
assertEquals("J", parent.getKeyBetweenChildren(child1, child2));
assertEquals("M", parent.getKeyBetweenChildren(child2, child3));
}
@Test
public void getExtremeKey_returnsFirstKeyBiggerThanParentKey_leftSide() {
Node parent = new Node(false);
parent.addKey("J");
parent.addKey("M");
Node child = new Node(true);
child.addKey("O");
child.addKey("P");
child.addKey("R");
parent.addChild(child);
assertEquals("O", child.getExtremeKeyComparedTo("M"));
}
@Test
public void getExtremeKey_returnsLastKeySmallerThanParentKey_rightSide() {
Node parent = new Node(false);
parent.addKey("J");
parent.addKey("M");
Node child = new Node(true);
child.addKey("K");
child.addKey("L");
parent.addChild(child);
assertEquals("L", child.getExtremeKeyComparedTo("M"));
}
@Test
public void createFromSplitResult_nodeALeftAndBRight() {
Node root = new Node(false);