diff --git a/BTree/.classpath b/BTree/.classpath
new file mode 100644
index 0000000..6361ddd
--- /dev/null
+++ b/BTree/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/BTree/.gitignore b/BTree/.gitignore
new file mode 100644
index 0000000..ae3c172
--- /dev/null
+++ b/BTree/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/BTree/.project b/BTree/.project
new file mode 100644
index 0000000..cc942bd
--- /dev/null
+++ b/BTree/.project
@@ -0,0 +1,17 @@
+
+
+ BTree
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/BTree/src/lab/B_Tree.java b/BTree/src/lab/B_Tree.java
index 645c532..2113189 100644
--- a/BTree/src/lab/B_Tree.java
+++ b/BTree/src/lab/B_Tree.java
@@ -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 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 getB_Tree() {
- /**
- * Add your code here
- */
- return new ArrayList<>();
+ ArrayList res = new ArrayList();
+ 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. The returned ArrayList contains the entries of the B-Tree
- * in ascending order.
- *
+ * ArrayList. 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 getInorderTraversal() {
- /**
- * Add your code here
- */
- return new ArrayList<>();
+ ArrayList 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();
}
}
\ No newline at end of file
diff --git a/BTree/src/lab/B_TreeNode.java b/BTree/src/lab/B_TreeNode.java
index f335753..98f8db7 100644
--- a/BTree/src/lab/B_TreeNode.java
+++ b/BTree/src/lab/B_TreeNode.java
@@ -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 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(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 inorderTraversal(){
+ ArrayList result = new ArrayList();
+
+ 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 list){
+ String name = (isRoot ? "root" : "node"+index);
+ String selfNode = name+"[label=\"*";
+ for(int i = 0; i < this.currentLoad*2; i += 2) {
+ selfNode += "|"+keys.get(i/2).getKey()+"|*";
+ }
+ 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
- */
-
-
}
\ No newline at end of file