boolean insert(Object x, int parentIndex) { if (isFull()) { // If full, you must split and promote splitNode before inserting Object splitNode = entries[nrElements / 2].element; BTreeNode rightSibling = split(); if (isRoot()) { // Grow a level splitRoot(splitNode, this, rightSibling); // Determine where to insert if (BTreeSet.this.compare(x, BTreeSet.this.root.entries[0].element) < 0) insert(x, 0); else rightSibling.insert(x, 1); } else { // Promote splitNode parent.insertSplitNode(splitNode, this, rightSibling, parentIndex); if (BTreeSet.this.compare(x, parent.entries[parentIndex].element) < 0) { return insert(x, parentIndex); } return rightSibling.insert(x, parentIndex + 1); } } else if (isLeaf()) { // If leaf, simply insert the non-duplicate element int insertAt = childToInsertAt(x, true); // Determine if the element already exists if (insertAt == -1) { return false; } insertNewElement(x, insertAt); BTreeSet.this.size++; return true; } else { // If not full and not leaf recursively find correct node to insert at int insertAt = childToInsertAt(x, true); return (insertAt == -1 ? false : entries[insertAt].child.insert(x, insertAt)); } return false; }
/* * Creates a new BTreeSet.root which contains only the splitNode and pointers * to it's left and right child. */ private void splitRoot(Object splitNode, BTreeNode left, BTreeNode right) { BTreeNode newRoot = new BTreeNode(null); newRoot.entries[0].element = splitNode; newRoot.entries[0].child = left; newRoot.entries[1] = new Entry(); newRoot.entries[1].child = right; newRoot.nrElements = 1; left.parent = right.parent = newRoot; BTreeSet.this.root = newRoot; }
boolean delete(Object x, int parentIndex) { int i = childToInsertAt(x, true); int priorParentIndex = parentIndex; BTreeNode temp = this; if (i != -1) { do { if (temp.entries[i] == null || temp.entries[i].child == null) return false; temp = temp.entries[i].child; priorParentIndex = parentIndex; parentIndex = i; i = temp.childToInsertAt(x, true); } while (i != -1); } // Now temp contains element to delete and temp's parentIndex is parentIndex if (temp.isLeaf()) { // If leaf and have more than MIN elements, simply delete if (temp.nrElements > MIN) { temp.deleteElement(x); BTreeSet.this.size--; return true; } // else - If leaf and have less than MIN elements, than prepare the BTreeSet for deletion temp.prepareForDeletion(parentIndex); temp.deleteElement(x); BTreeSet.this.size--; temp.fixAfterDeletion(priorParentIndex); return true; } // else - Only delete at leaf so first switch with successor than delete temp.switchWithSuccessor(x); parentIndex = temp.childToInsertAt(x, false) + 1; return temp.entries[parentIndex].child.delete(x, parentIndex); }
private void fixAfterDeletion(int parentIndex) { if (isRoot() || parent.isRoot()) return; // No fixing needed if (parent.nrElements < MIN) { // If parent lost it's n/2 element repair it BTreeNode temp = parent; temp.prepareForDeletion(parentIndex); if (temp.parent == null) return; // Root changed if (!temp.parent.isRoot() && temp.parent.nrElements < MIN) { // If need be recurse BTreeNode x = temp.parent.parent; int i = 0; // Find parent's parentIndex for (; i < entries.length; i++) if (x.entries[i].child == temp.parent) break; temp.parent.fixAfterDeletion(i); } } }
private Object nextElement() { if (currentNode.isLeaf()) { if (index < currentNode.nrElements) return currentNode.entries[index++].element; else if (!parentIndex .empty()) { // All elements have been returned, return successor of lastReturned if it // exists currentNode = currentNode.parent; index = ((Integer) parentIndex.pop()).intValue(); while (index == currentNode.nrElements) { if (parentIndex.empty()) break; currentNode = currentNode.parent; index = ((Integer) parentIndex.pop()).intValue(); } if (index == currentNode.nrElements) return null; // Reached root and he has no more children return currentNode.entries[index++].element; } else { // Your a leaf and the root if (index == currentNode.nrElements) return null; return currentNode.entries[index++].element; } } // else - You're not a leaf so simply find and return the successor of lastReturned currentNode = currentNode.entries[index].child; parentIndex.push(Integer.valueOf(index)); while (currentNode.entries[0].child != null) { currentNode = currentNode.entries[0].child; parentIndex.push(Integer.valueOf(0)); } index = 1; return currentNode.entries[0].element; }
public boolean remove(Object x) { if (x == null) return false; return root.delete(x, -1); }
public boolean contains(Object x) { return root.includes(x); }
/* * Public Methods */ public boolean add(Object x) throws IllegalArgumentException { if (x == null) throw new IllegalArgumentException(); return root.insert(x, -1); }
/* * This method is called only when stealLeft, stealRight, and mergeLeft could not be called, * the BTreeNode has the minimum number of elements, has a rightSibling, and the * rightSibling has more than the minimum number of elements. If after completion * parent has fewer than the minimum number of elements than the parents entries[0] * slot is left empty in anticipation of a recursive call to stealLeft, stealRight, * mergeLeft, or mergeRight to fix the parent. All of the before-mentioned methods * expect the parent to be in such a condition. */ private void mergeRight(int parentIndex) { BTreeNode p = parent; BTreeNode rs = p.entries[parentIndex + 1].child; if (isLeaf()) { // Don't worry about children entries[nrElements] = new Entry(); entries[nrElements].element = p.entries[parentIndex].element; nrElements++; for (int i = 0, nr = nrElements; i < rs.nrElements; i++, nr++) { entries[nr] = rs.entries[i]; nrElements++; } p.entries[parentIndex].element = p.entries[parentIndex + 1].element; if (p.nrElements == MIN && p != BTreeSet.this.root) { for (int x = parentIndex + 1, y = parentIndex; y >= 0; x--, y--) p.entries[x] = p.entries[y]; p.entries[0] = new Entry(); p.entries[0].child = rs; // So it doesn't think it's a leaf, this child will be deleted in the next // recursive call } else { for (int x = parentIndex + 1, y = parentIndex + 2; y <= p.nrElements; x++, y++) p.entries[x] = p.entries[y]; p.entries[p.nrElements] = null; } p.nrElements--; if (p.isRoot() && p.nrElements == 0) { // It's the root and it's empty BTreeSet.this.root = this; parent = null; } } else { // It's not a leaf entries[nrElements].element = p.entries[parentIndex].element; nrElements++; for (int x = nrElements + 1, y = 0; y <= rs.nrElements; x++, y++) { entries[x] = rs.entries[y]; rs.entries[y].child.parent = this; nrElements++; } nrElements--; p.entries[++parentIndex].child = this; if (p.nrElements == MIN && p != BTreeSet.this.root) { for (int x = parentIndex - 1, y = parentIndex - 2; y >= 0; x--, y--) p.entries[x] = p.entries[y]; p.entries[0] = new Entry(); } else { for (int x = parentIndex - 1, y = parentIndex; y <= p.nrElements; x++, y++) p.entries[x] = p.entries[y]; p.entries[p.nrElements] = null; } p.nrElements--; if (p.isRoot() && p.nrElements == 0) { // It's the root and it's empty BTreeSet.this.root = this; parent = null; } } }
/* * This method is called only when stealLeft and stealRight could not be called, * the BTreeNode has the minimum number of elements, has a leftSibling, and the * leftSibling has more than the minimum number of elements. If after completion * parent has fewer than the minimum number of elements than the parents entries[0] * slot is left empty in anticipation of a recursive call to stealLeft, stealRight, * mergeLeft, or mergeRight to fix the parent. All of the before-mentioned methods * expect the parent to be in such a condition. */ private void mergeLeft(int parentIndex) { BTreeNode p = parent; BTreeNode ls = p.entries[parentIndex - 1].child; if (isLeaf()) { // Don't worry about children int add = childToInsertAt(p.entries[parentIndex - 1].element, true); insertNewElement( p.entries[parentIndex - 1].element, add); // Could have been a successor switch p.entries[parentIndex - 1].element = null; for (int i = nrElements - 1, nr = ls.nrElements; i >= 0; i--) entries[i + nr] = entries[i]; for (int i = ls.nrElements - 1; i >= 0; i--) { entries[i] = ls.entries[i]; nrElements++; } if (p.nrElements == MIN && p != BTreeSet.this.root) { for (int x = parentIndex - 1, y = parentIndex - 2; y >= 0; x--, y--) p.entries[x] = p.entries[y]; p.entries[0] = new Entry(); p.entries[0].child = ls; // So p doesn't think it's a leaf this will be deleted in the next recursive call } else { for (int x = parentIndex - 1, y = parentIndex; y <= p.nrElements; x++, y++) p.entries[x] = p.entries[y]; p.entries[p.nrElements] = null; } p.nrElements--; if (p.isRoot() && p.nrElements == 0) { // It's the root and it's empty BTreeSet.this.root = this; parent = null; } } else { // I'm not a leaf but fixing the tree structure entries[0].element = p.entries[parentIndex - 1].element; entries[0].child = ls.entries[ls.nrElements].child; nrElements++; for (int x = nrElements, nr = ls.nrElements; x >= 0; x--) entries[x + nr] = entries[x]; for (int x = ls.nrElements - 1; x >= 0; x--) { entries[x] = ls.entries[x]; entries[x].child.parent = this; nrElements++; } if (p.nrElements == MIN && p != BTreeSet.this.root) { // Push everything to the right for (int x = parentIndex - 1, y = parentIndex - 2; y >= 0; x++, y++) { System.out.println(x + " " + y); p.entries[x] = p.entries[y]; } p.entries[0] = new Entry(); } else { // Either p.nrElements > MIN or p == BTreeSet.this.root so push everything to the // left for (int x = parentIndex - 1, y = parentIndex; y <= p.nrElements; x++, y++) p.entries[x] = p.entries[y]; p.entries[p.nrElements] = null; } p.nrElements--; if (p.isRoot() && p.nrElements == 0) { // p == BTreeSet.this.root and it's empty BTreeSet.this.root = this; parent = null; } } }