blueprint deletion btrees

This commit is contained in:
wgroeneveld 2018-04-04 08:25:15 +02:00
parent f29428f591
commit 01368089b1
4 changed files with 282 additions and 9 deletions

View File

@ -5,11 +5,15 @@ public class BTree {
private Node root;
private final int t;
public BTree(int t) {
this.root = Node.createRoot();
public BTree(Node node, int t) {
this.root = node;
this.t = t;
}
public BTree(int t) {
this(Node.createRoot(), t);
}
public Node getRoot() {
return root;
}
@ -29,6 +33,46 @@ public class BTree {
}
/**
* case 1: if x is a leaf and x has >= t keys, just delete it.
* case 2: if x is an internal node
* a) if x's left child has >= t keys, move the largest key to the key to delete.
* b) if x's right child has >= t keys, move the smallest key to the key to delete.
* c) if none of the children have >= t keys, merge the children and delete the key.
* case 3: if x is a leaf and x has == t - 1 keys, then
* a) if x has a sibling with at least t keys
* - move parent's key -> x
* - find extreme(key) sibling with at least t keys (left/right), move x's key -> parent
* - then proceed as case 1
* b) if x's sibling also has t - 1 keys
* - merge x with sibling: move parent's key -> x (as t key)
* - then delete that key
* @param key
*/
public void delete(String key) {
BTreeSearchResult searchResult = search(key);
if(!searchResult.isFound()) return;
Node node = searchResult.getNode();
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)) {
// 3.a
} else if(searchResult.getParent().getSiblingsOf(node).stream().allMatch(s -> s.getNumberOfKeys() == t - 1)) {
// 3.b
}
} else if(!node.isLeaf()) { // case 2
if(node.getLeftChild().getNumberOfKeys() >= t) {
// 2.a
} else if(node.getRightChild().getNumberOfKeys() >= t) {
// 2.b
} else {
// 2.c
}
}
}
private void insertNonFull(Node node, String key) {
if(node.isLeaf()) {
node.addKey(key);
@ -60,19 +104,19 @@ public class BTree {
}
public BTreeSearchResult search(String key) {
return searchInNode(root, key);
return searchInNode(root, key, null);
}
private BTreeSearchResult searchInNode(Node node, String key) {
private BTreeSearchResult searchInNode(Node node, String key, Node parent) {
int i = 0;
while(i < node.getNumberOfKeys() && key.compareTo(node.getKeys().get(i)) > 0) {
i++;
}
if(i < node.getNumberOfKeys() && key == node.getKeys().get(i)) {
return new BTreeSearchResult(node, i);
return new BTreeSearchResult(node, i, parent);
}
if(node.isLeaf()) return new BTreeSearchResult();
return searchInNode(node.getChildren().get(i), key);
return searchInNode(node.getChildren().get(i), key, node);
}
}

View File

@ -2,20 +2,25 @@ package be.brainbaking.datastructures.trees;
public class BTreeSearchResult {
private final Node parent;
private final Node node;
private final int index;
public BTreeSearchResult() {
node = null;
index = -1;
this(null, -1, null);
}
public boolean isFound() {
return node != null;
}
public BTreeSearchResult(Node node, int index) {
public Node getParent() {
return parent;
}
public BTreeSearchResult(Node node, int index, Node parent) {
this.node = node;
this.parent = parent;
this.index = index;
}

View File

@ -46,6 +46,27 @@ 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> 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));
}
return siblings;
}
public void addChild(Node node) {
addChild(children.size(), node);
}
@ -106,6 +127,14 @@ public class Node {
return keys;
}
public Node getLeftChild() {
return children.get(0);
}
public Node getRightChild() {
return children.get(children.size() - 1);
}
public boolean isLeaf() {
return leaf;
}
@ -119,4 +148,8 @@ public class Node {
return root;
}
public void deleteKey(String key) {
keys.remove(key);
}
}

View File

@ -7,8 +7,199 @@ import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
// deletion examples: https://www.youtube.com/watch?v=fKubKYzwDl0 - cases omgekeerde van p451
public class BTreeTest {
@Test
public void deleteCase1() {
Node root = new Node(false);
root.addKey("D");
root.addKey("G");
Node child1 = new Node(true);
child1.addKey("A");
child1.addKey("B");
child1.addKey("C");
Node child2 = new Node(true);
child2.addKey("E");
child2.addKey("F");
Node child3 = new Node(true);
child3.addKey("H");
child3.addKey("I");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
BTree tree = new BTree(root, 3);
tree.delete("B");
assertArrayEquals(Arrays.asList("A", "B").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
}
@Test
public void deleteCase2A() {
Node root = new Node(false);
root.addKey("Q");
root.addKey("U");
Node child1 = new Node(true);
child1.addKey("O");
child1.addKey("P");
Node child2 = new Node(true);
child2.addKey("R");
child2.addKey("S");
child2.addKey("T");
Node child3 = new Node(true);
child3.addKey("W");
child3.addKey("X");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
BTree tree = new BTree(root, 3);
tree.delete("U");
assertArrayEquals(Arrays.asList("Q", "T").toArray(), tree.getRoot().getKeys().toArray());
assertArrayEquals(Arrays.asList("O", "P").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
assertArrayEquals(Arrays.asList("R", "S").toArray(), tree.getRoot().getChildren().get(1).getKeys().toArray());
assertArrayEquals(Arrays.asList("W", "X").toArray(), tree.getRoot().getChildren().get(2).getKeys().toArray());
}
@Test
public void deleteCase2B() {
Node root = new Node(false);
root.addKey("I");
root.addKey("M");
Node child1 = new Node(true);
child1.addKey("G");
child1.addKey("H");
Node child2 = new Node(true);
child2.addKey("J");
child2.addKey("K");
child2.addKey("L");
Node child3 = new Node(true);
child3.addKey("O");
child3.addKey("P");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
BTree tree = new BTree(root, 3);
tree.delete("I");
assertArrayEquals(Arrays.asList("J", "M").toArray(), tree.getRoot().getKeys().toArray());
assertArrayEquals(Arrays.asList("G", "H").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
assertArrayEquals(Arrays.asList("K", "L").toArray(), tree.getRoot().getChildren().get(1).getKeys().toArray());
assertArrayEquals(Arrays.asList("O", "P").toArray(), tree.getRoot().getChildren().get(2).getKeys().toArray());
}
@Test
public void deleteCase2C() {
Node root = new Node(false);
root.addKey("R");
root.addKey("U");
root.addKey("X");
Node child1 = new Node(true);
child1.addKey("P");
child1.addKey("Q");
Node child2 = new Node(true);
child2.addKey("S");
child2.addKey("T");
Node child3 = new Node(true);
child3.addKey("V");
child3.addKey("W");
Node child4 = new Node(true);
child4.addKey("Y");
child4.addKey("Z");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
root.addChild(child4);
BTree tree = new BTree(root, 3);
tree.delete("U");
assertArrayEquals(Arrays.asList("R", "X").toArray(), tree.getRoot().getKeys().toArray());
assertArrayEquals(Arrays.asList("P", "Q").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
assertArrayEquals(Arrays.asList("S", "T", "V", "W").toArray(), tree.getRoot().getChildren().get(1).getKeys().toArray());
assertArrayEquals(Arrays.asList("Y", "Z").toArray(), tree.getRoot().getChildren().get(2).getKeys().toArray());
}
@Test
public void deleteCase3A() {
Node root = new Node(false);
root.addKey("J");
root.addKey("M");
Node child1 = new Node(true);
child1.addKey("G");
child1.addKey("H");
Node child2 = new Node(true);
child2.addKey("K");
child2.addKey("L");
Node child3 = new Node(true);
child3.addKey("O");
child3.addKey("P");
child3.addKey("R");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
BTree tree = new BTree(root, 3);
tree.delete("L");
assertArrayEquals(Arrays.asList("J", "O").toArray(), tree.getRoot().getKeys().toArray());
assertArrayEquals(Arrays.asList("K", "M").toArray(), tree.getRoot().getChildren().get(1).getKeys().toArray());
}
@Test
public void deleteCase3B() {
Node root = new Node(false);
root.addKey("Q");
root.addKey("T");
Node child1 = new Node(true);
child1.addKey("O");
child1.addKey("P");
Node child2 = new Node(true);
child2.addKey("R");
child2.addKey("S");
Node child3 = new Node(true);
child3.addKey("W");
child3.addKey("X");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
BTree tree = new BTree(root, 3);
tree.delete("S");
assertArrayEquals(Arrays.asList("Q").toArray(), tree.getRoot().getKeys().toArray());
assertArrayEquals(Arrays.asList("O", "P").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
assertArrayEquals(Arrays.asList("R", "T", "W", "X").toArray(), tree.getRoot().getChildren().get(1).getKeys().toArray());
}
@Test
public void searching_afterAddingExampleAndHavingToSplit() {
BTree tree = new BTree(4);