mirror of
https://github.com/tu-darmstadt-informatik/AuD18.git
synced 2025-12-13 09:55:49 +00:00
Start implementing BTree class
This commit is contained in:
parent
b0784f990f
commit
24a2536d65
7
BTree/.classpath
Normal file
7
BTree/.classpath
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
1
BTree/.gitignore
vendored
Normal file
1
BTree/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/bin/
|
||||
17
BTree/.project
Normal file
17
BTree/.project
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>BTree</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@ -1,6 +1,11 @@
|
||||
package lab;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import frame.*;
|
||||
|
||||
@ -17,75 +22,97 @@ import frame.*;
|
||||
|
||||
|
||||
public class B_Tree {
|
||||
|
||||
private final int t;
|
||||
private B_TreeNode root;
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
*
|
||||
* @param t minimum degree of the B-tree.
|
||||
* t can not be changed once a new B Tree object is created.
|
||||
*
|
||||
* t can not be changed once a new B Tree object is created.
|
||||
*
|
||||
*/
|
||||
|
||||
public B_Tree(int t) {
|
||||
/**
|
||||
* Add your code here
|
||||
*/
|
||||
|
||||
this.t = t;
|
||||
this.root = new B_TreeNode(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes as input the name of a file containing a sequence of
|
||||
* entries that should be inserted to the B-Tree in the order they appear in
|
||||
* the file. You cannot make any assumptions on the order of the entries nor
|
||||
* is it allowed to change the order given in the file. You can assume that the
|
||||
* file is located in the same directory as the executable program. The input
|
||||
* file is similar to the input file for lab 1. The return value is the number of
|
||||
* entries successfully inserted in the B-Tree.
|
||||
* entries that should be inserted to the B-Tree in the order they appear in
|
||||
* the file. You cannot make any assumptions on the order of the entries nor
|
||||
* is it allowed to change the order given in the file. You can assume that the
|
||||
* file is located in the same directory as the executable program. The input
|
||||
* file is similar to the input file for lab 1. The return value is the number of
|
||||
* entries successfully inserted in the B-Tree.
|
||||
*
|
||||
* @param filename name of the file containing the entries
|
||||
* @return returns the number of entries successfully inserted in the B-Tree.
|
||||
*/
|
||||
|
||||
|
||||
public int constructB_TreeFromFile (String filename) {
|
||||
/**
|
||||
* Add your code here
|
||||
*/
|
||||
return 0;
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
|
||||
String line;
|
||||
String[] parts;
|
||||
int insertionCount = 0;
|
||||
|
||||
// Read all lines
|
||||
while ((line = br.readLine()) != null) {
|
||||
// Create new entry from line parts separated by a semicolon
|
||||
parts = line.split(";");
|
||||
Entry entry = new Entry(parts[0], parts[1], parts[2]);
|
||||
|
||||
if(this.insert(entry))
|
||||
insertionCount += 1;
|
||||
}
|
||||
|
||||
return insertionCount;
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("File not found");
|
||||
return 0;
|
||||
} catch (IOException e) {
|
||||
System.out.println("IO Exception");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method inserts the entry insertEntry into the B-Tree. Note that you
|
||||
* have to deal with overflows if you want to insert an entry into a leaf which
|
||||
* already contains 2t - 1 entries. This method returns true if the insertion
|
||||
* of the entry insertEntry is successful and false if the key of this entry
|
||||
* already exists in the B-Tree.
|
||||
*
|
||||
* have to deal with overflows if you want to insert an entry into a leaf which
|
||||
* already contains 2t - 1 entries. This method returns true if the insertion
|
||||
* of the entry insertEntry is successful and false if the key of this entry
|
||||
* already exists in the B-Tree.
|
||||
*
|
||||
* @param insertEntry entry to insert into the B-Tree
|
||||
* @return returns true if the entry insertEntry is successfully inserted
|
||||
* false if the entry already exists in the B-Tree
|
||||
* false if the entry already exists in the B-Tree
|
||||
*/
|
||||
|
||||
|
||||
public boolean insert(Entry insertEntry) {
|
||||
/**
|
||||
* Add your code here
|
||||
*/
|
||||
return true;
|
||||
|
||||
if(root.isFull()) {
|
||||
B_TreeNode newRoot = new B_TreeNode(this.t);
|
||||
newRoot.makeNonLeaf();
|
||||
newRoot.setPointer(0, root);
|
||||
newRoot.splitChild(root);
|
||||
this.root = newRoot;
|
||||
}
|
||||
|
||||
return root.insert(insertEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method deletes the entry from the B-Tree structure, having deleteKey
|
||||
* as key. In this method you have to distinguish between two cases:
|
||||
* 1. The entry, having deleteKey as key, is located in an internal node.
|
||||
* 2. The entry, having deleteKey as key, is located in a leaf.
|
||||
* This method returns the entry, having deleteKey as key if the deletion is
|
||||
* successful and null if the key deleteKey is not found in any entry of the
|
||||
* B-Tree.
|
||||
*
|
||||
* as key. In this method you have to distinguish between two cases:
|
||||
* 1. The entry, having deleteKey as key, is located in an internal node.
|
||||
* 2. The entry, having deleteKey as key, is located in a leaf.
|
||||
* This method returns the entry, having deleteKey as key if the deletion is
|
||||
* successful and null if the key deleteKey is not found in any entry of the
|
||||
* B-Tree.
|
||||
*
|
||||
* @param deleteKey key of the entry to delete from the B-Tree
|
||||
* @return returns the deleted entry if the deletion ends successfully
|
||||
* null if the entry is not found in the B-Tree
|
||||
* null if the entry is not found in the B-Tree
|
||||
*/
|
||||
|
||||
|
||||
@ -98,83 +125,65 @@ public class B_Tree {
|
||||
|
||||
/**
|
||||
* This method searches in the B-Tree for the entry with key searchKey. It
|
||||
* returns the entry, having searchKey as key if such an entry is found, null
|
||||
* otherwise.
|
||||
*
|
||||
* returns the entry, having searchKey as key if such an entry is found, null
|
||||
* otherwise.
|
||||
*
|
||||
* @param searchKey key of the entry to find in the B-Tree
|
||||
* @return returns the entry having searchKey as key if such an entry exists
|
||||
* null if the entry is not found in the B-Tree
|
||||
* null if the entry is not found in the B-Tree
|
||||
*/
|
||||
|
||||
|
||||
public Entry find(String searchKey) {
|
||||
/**
|
||||
* Add your code here
|
||||
*/
|
||||
return new Entry();
|
||||
return root.find(searchKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a ArrayList<String> containing the output B-Tree.
|
||||
* The output should be directly interpretable dot code.
|
||||
* Each item in the ArrayList corresponds to one line of the output
|
||||
* tree. The nodes of the output tree should only
|
||||
* contain the keys of the entries and not the data.
|
||||
*
|
||||
* The output should be directly interpretable dot code.
|
||||
* Each item in the ArrayList corresponds to one line of the output
|
||||
* tree. The nodes of the output tree should only
|
||||
* contain the keys of the entries and not the data.
|
||||
*
|
||||
* @return returns the output B-Tree in directly interpretable dot code
|
||||
*/
|
||||
|
||||
*/
|
||||
public ArrayList<String> getB_Tree() {
|
||||
/**
|
||||
* Add your code here
|
||||
*/
|
||||
return new ArrayList<>();
|
||||
ArrayList<String> res = new ArrayList<String>();
|
||||
res.add("digraph{");
|
||||
res.add("node[shape=record];");
|
||||
root.getDotCode(1, true, res);
|
||||
res.add("}");
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the height of the B-Tree
|
||||
* If the B-Tree is empty this method should return 0.
|
||||
*
|
||||
* If the B-Tree is empty this method should return 0.
|
||||
*
|
||||
* @return returns the height of the B-Tree
|
||||
*/
|
||||
|
||||
|
||||
public int getB_TreeHeight() {
|
||||
/**
|
||||
* Add your code here
|
||||
*/
|
||||
return 0;
|
||||
return root.getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method traverses the B-Tree in inorder and adds each entry to a
|
||||
* ArrayList<Entry>. The returned ArrayList contains the entries of the B-Tree
|
||||
* in ascending order.
|
||||
*
|
||||
* ArrayList<Entry>. The returned ArrayList contains the entries of the B-Tree
|
||||
* in ascending order.
|
||||
*
|
||||
* @return returns the entries stored in the B-Tree in ascending order
|
||||
*/
|
||||
|
||||
|
||||
public ArrayList<Entry> getInorderTraversal() {
|
||||
/**
|
||||
* Add your code here
|
||||
*/
|
||||
return new ArrayList<>();
|
||||
ArrayList<Entry> res = root.inorderTraversal();
|
||||
System.out.println(res.stream().map(Object::toString).collect(Collectors.joining(", ")));
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the number of entries in the B-Tree (not the number
|
||||
* of nodes).
|
||||
*
|
||||
*
|
||||
* of nodes).
|
||||
*
|
||||
* @return returns the size of the B-Tree, i.e., the number of entries stored in the B-Tree
|
||||
*/
|
||||
|
||||
|
||||
public int getB_TreeSize() {
|
||||
/**
|
||||
* Add your code here
|
||||
*/
|
||||
return 0;
|
||||
return root.getSize();
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,9 @@
|
||||
package lab;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import frame.Entry;
|
||||
|
||||
/*
|
||||
* Implements a node of a B-Tree
|
||||
*
|
||||
@ -9,25 +13,235 @@ package lab;
|
||||
*/
|
||||
|
||||
|
||||
|
||||
public class B_TreeNode {
|
||||
|
||||
private ArrayList<Entry> keys;
|
||||
private B_TreeNode[] pointers;
|
||||
private int currentLoad = 0;
|
||||
private boolean isLeaf = true;
|
||||
private final int t;
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
*
|
||||
* @param t minimum degree of the B-tree
|
||||
*
|
||||
*/
|
||||
|
||||
public B_TreeNode(int t) {
|
||||
/**
|
||||
* Add your code here
|
||||
*/
|
||||
keys = new ArrayList<Entry>(t*2-1);
|
||||
pointers = new B_TreeNode[t*2];
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public Entry find(String searchKey) {
|
||||
Entry dummy = new Entry(searchKey, "", "");
|
||||
|
||||
System.out.println("Searching for "+searchKey+" in "+this);
|
||||
|
||||
int index = getIndexOf(dummy);
|
||||
|
||||
if(index > -1) {
|
||||
System.out.println("Is here!");
|
||||
return keys.get(index);
|
||||
}
|
||||
else if(isLeaf) {
|
||||
System.out.println("Is not in leaf -> is not in tree");
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
System.out.println("Pointing to "+getPointerTowards(dummy));
|
||||
return getPointerTowards(dummy).find(searchKey);
|
||||
}
|
||||
}
|
||||
|
||||
public int getIndexOf(Entry entry) {
|
||||
for(int i = 0; i < this.currentLoad; i++) {
|
||||
if(entry.compareTo(keys.get(i)) == 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean insert(Entry entry) {
|
||||
if(isLeaf)
|
||||
return getIndexOf(entry) > 0 ? false : insertValue(entry);
|
||||
|
||||
if(this.isFull())
|
||||
throw new RuntimeException("Insert expects non-full root node");
|
||||
|
||||
B_TreeNode pointer = getPointerTowards(entry);
|
||||
System.out.println(pointer);
|
||||
if(pointer.isFull()) {
|
||||
this.splitChild(pointer);
|
||||
pointer = getPointerTowards(entry);
|
||||
}
|
||||
return pointer.insert(entry);
|
||||
}
|
||||
|
||||
private boolean insertValue(Entry entry) {
|
||||
if(!this.isLeaf)
|
||||
throw new RuntimeException("Trying to insert value into non-leaf node");
|
||||
if(this.isFull())
|
||||
throw new RuntimeException("Trying to insert value into full leaf node");
|
||||
|
||||
int i = 0;
|
||||
while(i < this.currentLoad && entry.compareTo(keys.get(i)) > 0) {
|
||||
i += 1;
|
||||
}
|
||||
keys.add(i, entry);
|
||||
this.currentLoad += 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private B_TreeNode getPointerTowards(Entry entry) {
|
||||
if(this.isLeaf)
|
||||
throw new RuntimeException("Trying to get pointer from leaf node");
|
||||
|
||||
int i = 0;
|
||||
while(i < this.currentLoad && entry.compareTo(keys.get(i)) > 0) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if(pointers[i] == null)
|
||||
throw new RuntimeException("Non-leaf node with capacity "+currentLoad+" does not have pointer "+i);
|
||||
|
||||
return pointers[i];
|
||||
}
|
||||
|
||||
public void splitChild(B_TreeNode child) {
|
||||
|
||||
if(this.isFull())
|
||||
throw new RuntimeException("Trying to split child of full node");
|
||||
|
||||
System.out.println("SPLIT "+child);
|
||||
|
||||
B_TreeNode newRight = new B_TreeNode(this.t);
|
||||
for(int i = 0; i < t-1; i++) {
|
||||
newRight.insert(child.getEntry(i+t));
|
||||
}
|
||||
if(!child.isLeaf()) {
|
||||
newRight.makeNonLeaf();
|
||||
for(int i = 0; i < t; i++) {
|
||||
newRight.setPointer(i, child.getPointer(i+t));
|
||||
}
|
||||
}
|
||||
Entry median = child.getEntry(t-1);
|
||||
child.setCurrentLoad(t-1);
|
||||
int i = this.currentLoad;
|
||||
while(pointers[i] != child) {
|
||||
pointers[i+1] = pointers[i];
|
||||
i -= 1;
|
||||
}
|
||||
pointers[i+1] = newRight;
|
||||
keys.add(i, median);
|
||||
currentLoad += 1;
|
||||
|
||||
System.out.println("New left node: "+child);
|
||||
System.out.println("Median: "+median);
|
||||
System.out.println("New right node: "+newRight);
|
||||
}
|
||||
|
||||
public ArrayList<Entry> inorderTraversal(){
|
||||
ArrayList<Entry> result = new ArrayList<Entry>();
|
||||
|
||||
if(pointers[0] != null) {
|
||||
result.addAll(pointers[0].inorderTraversal());
|
||||
}
|
||||
|
||||
for(int i = 0; i < this.currentLoad; i++) {
|
||||
result.add(keys.get(i));
|
||||
if(pointers[i+1] != null) {
|
||||
result.addAll(pointers[i+1].inorderTraversal());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
if(isLeaf)
|
||||
return 0;
|
||||
|
||||
int maxHeight = 0;
|
||||
int cHeight;
|
||||
for(int i = 0; i <= this.currentLoad; i++) {
|
||||
if(pointers[i] != null) {
|
||||
cHeight = pointers[i].getHeight();
|
||||
if(cHeight > maxHeight)
|
||||
maxHeight = cHeight;
|
||||
}
|
||||
}
|
||||
return maxHeight + 1;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
int res = this.currentLoad;
|
||||
for(int i = 0; i <= this.currentLoad; i++) {
|
||||
if(pointers[i] != null)
|
||||
res += pointers[i].getSize();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
return this.currentLoad >= this.t * 2 - 1;
|
||||
}
|
||||
|
||||
public boolean isLeaf() {
|
||||
return this.isLeaf;
|
||||
}
|
||||
|
||||
public void makeNonLeaf() {
|
||||
this.isLeaf = false;
|
||||
}
|
||||
|
||||
public Entry getEntry(int i) {
|
||||
return keys.get(i);
|
||||
}
|
||||
|
||||
public B_TreeNode getPointer(int i) {
|
||||
if(i > this.currentLoad)
|
||||
throw new RuntimeException("Trying to get non-existent pointer");
|
||||
return this.pointers[i];
|
||||
}
|
||||
|
||||
public void setPointer(int i, B_TreeNode pointer) {
|
||||
if(i > this.currentLoad)
|
||||
throw new RuntimeException("Trying to set non-existent pointer");
|
||||
if(isLeaf)
|
||||
throw new RuntimeException("Trying to set pointer on leaf");
|
||||
this.pointers[i] = pointer;
|
||||
}
|
||||
|
||||
public void setCurrentLoad(int i) {
|
||||
this.currentLoad = i;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String res = "";
|
||||
for(int i = 0; i < this.currentLoad; i++) {
|
||||
res += keys.get(i).getKey() + ", ";
|
||||
}
|
||||
return "["+res+"]";
|
||||
}
|
||||
|
||||
public int getDotCode(int index, boolean isRoot, ArrayList<String> list){
|
||||
String name = (isRoot ? "root" : "node"+index);
|
||||
String selfNode = name+"[label=\"<f0>*";
|
||||
for(int i = 0; i < this.currentLoad*2; i += 2) {
|
||||
selfNode += "|<f"+i+">"+keys.get(i/2).getKey()+"|<f"+(i+1)+">*";
|
||||
}
|
||||
selfNode += "\"];";
|
||||
list.add(selfNode);
|
||||
|
||||
if(isLeaf)
|
||||
return index;
|
||||
|
||||
for(int i = 0; i <= this.currentLoad; i++) {
|
||||
list.add(name+":f"+(i*2)+"->node"+(index+1));
|
||||
index = pointers[i].getDotCode(index+1, false, list);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add your code here
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user