deletion btree rest
This commit is contained in:
parent
01368089b1
commit
959e23575d
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue