Java tutorial
//package termproject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; /** * (2,4) Search Tree * * Description: An ADT for a (2,4) Search Tree as described on page 451 of * the Data Structures and Algorithms in Java textbook. * * Date Created: December, 2008 * @author Alex Laird, Wes Perrien * @version 1.0 */ public class TwoFourTree implements Dictionary { private Comparator treeComp; private int size = 0; private TFNode treeRoot = null; /** * Default constructor which assigns the comparator for the tree. * * @param comp Comparator the comparator to be assigned */ public TwoFourTree(Comparator comp) { treeComp = comp; } /** * Returns the current size of the tree. * * @return int the current size of the tree. */ public int size() { return size; } /** * Returns true if the tree is empty, otherwise false. * * @return boolean whether the tree is empty or not */ public boolean isEmpty() { return (size == 0); } /** * Returns a pointer to the root node of the tree. * * @return TFNode the root node */ public TFNode root() { return treeRoot; } /** * Finds an the first element in the tree with the specified key. * * @param key Object the key that is to be found in the tree * @return Object the Item that contains the specified key * @throws ElementNotFoundException if the key is not found in the tree */ public Object findElement(Object key) throws ElementNotFoundException { TFNode node = firstGreaterOrEqualNode(key, root()); int itemIndex = firstGreaterOrEqualItem(key, node); if (itemIndex == -1) throw new ElementNotFoundException(); if (treeComp.isEqual(key, ((Item) node.getItem(itemIndex)).key())) return node.getItem(itemIndex); else throw new ElementNotFoundException(); } /** * Inserts an Item with the specified key and element into the tree at it's * proper location. This function determines the in order successor based on * the specified key to find the proper location. * * @param key Object the key to be used for the inserted Item * @param element Object the element to be used for the inserted Item */ public void insertElement(Object key, Object element) { Item newItem = new Item(key, element); // if this is the first element, make a root node if (size() == 0) { treeRoot = new TFNode(); treeRoot.addItem(0, newItem); size++; return; } // find the node that contains the first greater or equal item TFNode greatest = findInsertionPointer(newItem.key(), root()); if (greatest != null) { // find greatest or equal item within node int index = firstGreaterOrEqualItem(newItem.key(), greatest); // if a greater or equal item was not found in node, add at end if (index == -1) index = greatest.numItems(); // insert item at proper location greatest.insertItem(index, newItem); } // if a greater or equal node was not found, insert at root else { greatest = treeRoot; // walks to the far right child while (greatest.getChild(greatest.numItems()) != null) greatest = greatest.getChild(greatest.numItems()); greatest.addItem(greatest.numItems(), newItem); } // incremet tree size size++; // if the insert caused a node to be greater than the max allowed size // a node split is required if (greatest.numItems() == greatest.maxItems() + 1) { nodePop(greatest); } } /** * Removes the first element from the tree that matches the specified key. * * @param key Object the key to be removed by the first found element * @return Object the Item that contains the specified key * @throws ElementNotFoundException if the key is not found in the tree */ public Object removeElement(Object key) throws ElementNotFoundException { // ensure that the element is in the tree and find it findElement(key); TFNode node = firstGreaterOrEqualNode(key, root()); TFNode inOrderSuccessor = null; Object element; // find the index of the element within the node int location = firstGreaterOrEqualItem(key, node); // if the node is internal if (node.getChild(location + 1) != null) { inOrderSuccessor = node.getChild(location + 1); // find the in order successor while (inOrderSuccessor.getChild(0) != null) inOrderSuccessor = inOrderSuccessor.getChild(0); node.insertItem(location, inOrderSuccessor.removeItem(0)); location++; } // remove the item from the tree element = node.removeItem(location); // rebalance the tree if the node has become empty if (node.numItems() == 0 && node != root()) rebalance(node); // rebalance tree if in order successor has become empty if (inOrderSuccessor != null && inOrderSuccessor.numItems() == 0) rebalance(inOrderSuccessor); return element; } /** * Determines whether the specified node has a left sibling or not. If it does * have a left sibling, this method returns the index to the left sibling. * * @param node TFNode the node to be checked for a left sibling * @return int -1 if there is no left sibling, otherwise the index of the left sibling */ protected int hasLeftSibling(TFNode node) { int childIndex; // find the index in the parent of the current node for (childIndex = 0; childIndex < 4; childIndex++) { if (node.getParent().getChild(childIndex) == node) break; } if (childIndex != 0 && node.getParent().getChild(childIndex - 1) != null) // return the index of the left sibling return childIndex - 1; else // no left sibling exists return -1; } /** * Determines whether the specified node has a right sibling or not. If it does * have a right sibling, this method returns the index to the right sibling. * * @param node TFNode the node to be checked for a right sibling * @return int -1 if there is no right sibling, otherwise the index of the right sibling */ protected int hasRightSibling(TFNode node) { int childIndex; // find the index in the parent of the current node for (childIndex = 0; childIndex < 4; childIndex++) { if (node.getParent().getChild(childIndex) == node) break; } if (childIndex != 3 && node.getParent().getChild(childIndex + 1) != null) // return the index of the right sibling return childIndex + 1; else // no right sibling exists return -1; } /** * This method will rebalance if needed, usually directly following a remove. * * @param node TFNode the node to be the starting point for rebalance */ protected void rebalance(TFNode node) { // check siblings int leftSibIndex = hasLeftSibling(node); int rightSibIndex = hasRightSibling(node); TFNode leftSib = null; TFNode rightSib = null; TFNode parent = node.getParent(); TFNode newNode = null; if (leftSibIndex != -1) { // get the left sibling leftSib = parent.getChild(leftSibIndex); } if (rightSibIndex != -1) { // get the right sibling rightSib = parent.getChild(rightSibIndex); } // transfer from left sibling if (leftSibIndex != -1 && leftSib.numItems() > 1) { // insert parent into index 0 node.insertItem(0, parent.getItem(leftSibIndex)); // make left sibling's most right child the first child here node.setChild(0, leftSib.getChild(leftSib.numItems())); if (node.getChild(0) != null) node.getChild(0).setParent(node); // store the last pointer reference TFNode pointer = leftSib.getChild(leftSib.numItems() - 1); // make left sibling's greatest item the new parent parent.replaceItem(leftSibIndex, leftSib.removeItem(leftSib.numItems() - 1)); // reset the last pointer leftSib.setChild(leftSib.numItems(), pointer); } // transfer from right sibling else if (rightSibIndex != -1 && rightSib.numItems() > 1) { // insert parent into index 0 node.insertItem(0, parent.getItem(rightSibIndex - 1)); // make right sibling's first child the last child here node.setChild(0, rightSib.getChild(0)); if (node.getChild(0) != null) node.getChild(0).setParent(node); // store the third last pointer reference TFNode pointer = rightSib.getChild(0); // make right sibling's first item the new parent parent.replaceItem(rightSibIndex - 1, rightSib.removeItem(0)); // reset the last pointer rightSib.setChild(rightSib.numItems(), pointer); } // neither sibling has enough elements else { // left fusion if (leftSib != null && leftSib.numItems() == 1) { // store nodes pointer TFNode pointer = node.getChild(0); if (treeComp.isLessThan(((Item) leftSib.getItem(0)).key(), ((Item) parent.getItem(leftSibIndex)).key())) leftSib.addItem(1, parent.removeItem(leftSibIndex)); else leftSib.insertItem(0, parent.removeItem(leftSibIndex)); // reset the last pointer leftSib.setChild(leftSib.numItems(), pointer); if (pointer != null) pointer.setParent(leftSib); parent.setChild(leftSibIndex, leftSib); newNode = leftSib; } // right fusion else { // store the nodes pointer TFNode pointer = node.getChild(rightSib.numItems()); if (treeComp.isLessThan(((Item) rightSib.getItem(0)).key(), ((Item) parent.getItem(rightSibIndex - 1)).key())) rightSib.addItem(1, node.getParent().removeItem(rightSibIndex - 1)); else rightSib.insertItem(0, node.getParent().removeItem(rightSibIndex - 1)); // reset the first pointer rightSib.setChild(0, pointer); if (pointer != null) pointer.setParent(rightSib); parent.setChild(rightSibIndex - 1, rightSib); newNode = rightSib; } } // rebalance parent recursively if it has zero items and is not he parent if (parent.numItems() == 0) { if (parent != root()) rebalance(parent); else { treeRoot = newNode; newNode.setParent(null); size--; } } node = null; } /** * Searches the tree until it finds a node with an item that is greater than * or equal to the specified key. * * @param key Object the key to be compared against * @param node TFNode the node to be the starting point, usually the root * @return TFNode the node that holds the first greater or equal item */ protected TFNode firstGreaterOrEqualNode(Object key, TFNode start) { // recursive exit condition if (start == null) return null; int index = firstGreaterOrEqualItem(key, start); if (index == -1) { index = start.numItems(); return firstGreaterOrEqualNode(key, start.getChild(index)); } if (treeComp.isLessThan(key, ((Item) start.getItem(index)).key())) return firstGreaterOrEqualNode(key, start.getChild(index)); else if (treeComp.isGreaterThan(key, ((Item) start.getItem(index)).key())) return firstGreaterOrEqualNode(key, start.getChild(index + 1)); else return start; } /** * Searches the node until it finds a node that is greater than or equal to * the specified key. * * @param key Object the key to be compared against * @param node TFNode the node to be searched * @return int the index of the first greater than or equal item */ protected int firstGreaterOrEqualItem(Object key, TFNode node) throws ElementNotFoundException { if (node == null) throw new ElementNotFoundException(); // find first greater or equal item within the node for (int i = 0; i < node.numItems(); i++) { if (treeComp.isGreaterThanOrEqualTo(((Item) node.getItem(i)).key(), key)) return i; } // no greater or equal item was found return -1; } /** * Searches the tree until it finds a node with an item that is greater than * or equal to the specified key. This is the point at which it will insert * the a new node. * * @param key Object the key to be compared against * @param start TFNode the node to be the starting point, usually the root * @return TFNode the node that holds the first greater or equal item */ protected TFNode findInsertionPointer(Object key, TFNode start) { // exit condition for recursion if (start == null) return null; int index = firstGreaterOrEqualItem(key, start); // if a greater or equal item was not found in node, add at end if (index == -1) index = start.numItems(); // continue searching down tree TFNode node = findInsertionPointer(key, start.getChild(index)); if (node == null) return start; return node; } /** * Pops the third item out of a node and sends it to the parent, thus creating * the children nodes off of that parent then. Essentially a node split. Usually * called directly after an insert if the insert causes a node to become too full. * * @param left TFNode the node to be split */ protected void nodePop(TFNode left) { TFNode parent; TFNode right = new TFNode(); int index; // if no parent exists, we are the root if (left.getParent() == null) { parent = new TFNode(); treeRoot = parent; index = 0; } else { parent = left.getParent(); index = firstGreaterOrEqualItem(((Item) left.getItem(2)).key(), parent); // if a greater or equal item was not found in node, add at end if (index == -1) index = parent.numItems(); } // insert items in new locations parent.insertItem(index, left.getItem(2)); right.addItem(0, left.getItem(3)); // set new child pointers parent.setChild(index, left); parent.setChild(index + 1, right); // set parent pointers left.setParent(parent); right.setParent(parent); // conditions if the node has more than three children if (left.getChild(3) != null) { right.setChild(0, left.getChild(3)); right.getChild(0).setParent(right); } if (left.getChild(4) != null) { right.setChild(1, left.getChild(4)); right.getChild(1).setParent(right); } // store the third pointer reference TFNode pointer = left.getChild(2); // remove the two items left.removeItem(2); left.removeItem(2); // reassign the child which was lost in the remove left.setChild(2, pointer); // check to see if the parent is too full now; call recursion if (parent.numItems() == parent.maxItems() + 1) nodePop(parent); } /** * The main method which the program executes from and which handles all * testing and input/output. * * @param args String[] */ public static void main(String[] args) throws IOException { Comparator myComp = new IntegerComparator(); TwoFourTree myTree = new TwoFourTree(myComp); TwoFourTree firstTree = new TwoFourTree(myComp); TwoFourTree secondTree = new TwoFourTree(myComp); BufferedReader myReader = new BufferedReader(new InputStreamReader(System.in)); String input; boolean go = true; while (go == true) { System.out.print( "Format like this: -a 37 to add a 37 to the tree. -r 37 to remove a 37 from the tree: "); input = myReader.readLine(); if (input.substring(0, 2).equals("-a")) { Integer myInt = new Integer(input.substring(3, input.length())); myTree.insertElement(myInt, myInt); myTree.printAllElements(); } else if (input.substring(0, 2).equals("-r")) { Integer myInt = new Integer(input.substring(3, input.length())); myTree.removeElement(myInt); myTree.printAllElements(); } else System.out.print("\nYou're bad!"); System.out.print("\n"); } /*System.out.println("Loading firstTree with values ..."); Integer firstInt1 = new Integer(20); firstTree.insertElement(firstInt1, firstInt1); Integer firstInt2 = new Integer(50); firstTree.insertElement(firstInt2, firstInt2); Integer firstInt3 = new Integer(30); firstTree.insertElement(firstInt3, firstInt3); Integer firstInt4 = new Integer(40); firstTree.insertElement(firstInt4, firstInt4); Integer firstInt5 = new Integer(15); firstTree.insertElement(firstInt5, firstInt5); Integer firstInt6 = new Integer(35); firstTree.insertElement(firstInt6, firstInt6); Integer firstInt7 = new Integer(55); firstTree.insertElement(firstInt7, firstInt7); Integer firstInt8 = new Integer(38); firstTree.insertElement(firstInt8, firstInt8); Integer firstInt9 = new Integer(17); firstTree.insertElement(firstInt9, firstInt9); Integer firstInt10 = new Integer(37); firstTree.insertElement(firstInt10, firstInt10); Integer firstInt11 = new Integer(16); firstTree.insertElement(firstInt11, firstInt11); Integer firstInt12 = new Integer(36); firstTree.insertElement(firstInt12, firstInt12); Integer firstInt13 = new Integer(15); firstTree.insertElement(firstInt13, firstInt13); Integer firstInt14 = new Integer(36); firstTree.insertElement(firstInt14, firstInt14); Integer firstInt15 = new Integer(30); firstTree.insertElement(firstInt15, firstInt15); Integer firstInt16 = new Integer(34); firstTree.insertElement(firstInt16, firstInt16); Integer firstInt17 = new Integer(34); firstTree.insertElement(firstInt17, firstInt17); Integer firstInt18 = new Integer(30); firstTree.insertElement(firstInt18, firstInt18); Integer firstInt19 = new Integer(30); firstTree.insertElement(firstInt18, firstInt18); System.out.println("firstTree is fully loaded as follows:"); firstTree.printAllElements(); System.out.println("Checking parent/child connections ..."); firstTree.checkTree(firstTree.root()); System.out.println("All parent/child connections valid."); System.out.println("\nRemove 30"); firstTree.removeElement(30); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 30"); firstTree.removeElement(30); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 30"); firstTree.removeElement(30); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 30"); firstTree.removeElement(30); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 15"); firstTree.removeElement(15); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 55"); firstTree.removeElement(55); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 35"); firstTree.removeElement(35); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 38"); firstTree.removeElement(38); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 40"); firstTree.removeElement(40); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 36"); firstTree.removeElement(36); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 17"); firstTree.removeElement(17); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 34"); firstTree.removeElement(34); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 34"); firstTree.removeElement(34); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 36"); firstTree.removeElement(36); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 20"); firstTree.removeElement(20); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 37"); firstTree.removeElement(37); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 16"); firstTree.removeElement(16); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 50"); firstTree.removeElement(50); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println(""); System.out.println("Remove 15"); firstTree.removeElement(15); System.out.println("Removed successfully. Print new tree:"); firstTree.printAllElements(); System.out.println("done"); System.out.println("\n\nLoading secondTree with values ..."); Integer secondInt1 = new Integer(47); secondTree.insertElement(secondInt1, secondInt1); Integer secondInt2 = new Integer(83); secondTree.insertElement(secondInt2, secondInt2); Integer secondInt3 = new Integer(22); secondTree.insertElement(secondInt3, secondInt3); Integer secondInt4 = new Integer(16); secondTree.insertElement(secondInt4, secondInt4); Integer secondInt5 = new Integer(49); secondTree.insertElement(secondInt5, secondInt5); Integer secondInt6 = new Integer(100); secondTree.insertElement(secondInt6, secondInt6); Integer secondInt7 = new Integer(38); secondTree.insertElement(secondInt7, secondInt7); Integer secondInt8 = new Integer(3); secondTree.insertElement(secondInt8, secondInt8); Integer secondInt9 = new Integer(53); secondTree.insertElement(secondInt9, secondInt9); Integer secondInt10 = new Integer(66); secondTree.insertElement(secondInt10, secondInt10); Integer secondInt11 = new Integer(19); secondTree.insertElement(secondInt11, secondInt11); Integer secondInt12 = new Integer(23); secondTree.insertElement(secondInt12, secondInt12); Integer secondInt13 = new Integer(24); secondTree.insertElement(secondInt13, secondInt13); Integer secondInt14 = new Integer(88); secondTree.insertElement(secondInt14, secondInt14); Integer secondInt15 = new Integer(1); secondTree.insertElement(secondInt15, secondInt15); Integer secondInt16 = new Integer(97); secondTree.insertElement(secondInt16, secondInt16); Integer secondInt17 = new Integer(94); secondTree.insertElement(secondInt17, secondInt17); Integer secondInt18 = new Integer(35); secondTree.insertElement(secondInt18, secondInt18); Integer secondInt19 = new Integer(51); secondTree.insertElement(secondInt19, secondInt19); System.out.println("firstTree is fully loaded as follows:"); secondTree.printAllElements(); System.out.println("Checking parent/child connections ..."); secondTree.checkTree(secondTree.root()); System.out.println("All parent/child connections valid."); System.out.println("\nRemove 19"); secondTree.removeElement(19); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 3"); secondTree.removeElement(3); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 66"); secondTree.removeElement(66); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 88"); secondTree.removeElement(88); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 94"); secondTree.removeElement(94); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 100"); secondTree.removeElement(100); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 97"); secondTree.removeElement(97); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 47"); secondTree.removeElement(47); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 53"); secondTree.removeElement(53); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 38"); secondTree.removeElement(38); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 24"); secondTree.removeElement(24); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 83"); secondTree.removeElement(83); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 49"); secondTree.removeElement(49); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 23"); secondTree.removeElement(23); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 51"); secondTree.removeElement(51); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 1"); secondTree.removeElement(1); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 22"); secondTree.removeElement(22); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 16"); secondTree.removeElement(16); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println(""); System.out.println("Remove 35"); secondTree.removeElement(35); System.out.println("Removed successfully. Print new tree:"); secondTree.printAllElements(); System.out.println("done");*/ } public void printAllElements() { int indent = 0; if (root() == null) { System.out.println("The tree is empty"); } else { printTree(root(), indent); } } public void printTree(TFNode start, int indent) { if (start == null) { return; } for (int i = 0; i < indent; i++) { System.out.print(" "); } printTFNode(start); indent += 4; int numChildren = start.numItems() + 1; for (int i = 0; i < numChildren; i++) { printTree(start.getChild(i), indent); } } public void printTFNode(TFNode node) { int numItems = node.numItems(); for (int i = 0; i < numItems; i++) { System.out.print(((Item) node.getItem(i)).element() + " "); } System.out.println(); } // checks if tree is properly hooked up, i.e., children point to parents public void checkTree(TFNode start) { if (start == null) { return; } if (start.getParent() != null) { TFNode parent = start.getParent(); int childIndex = 0; for (childIndex = 0; childIndex <= parent.numItems(); childIndex++) { if (parent.getChild(childIndex) == start) { break; } } // if child wasn't found, print problem if (childIndex > parent.numItems()) { System.out.println("Child to parent confusion"); printTFNode(start); } } if (start.getChild(0) != null) { for (int childIndex = 0; childIndex <= start.numItems(); childIndex++) { if (start.getChild(childIndex).getParent() != start) { System.out.println("Parent to child confusion"); printTFNode(start); } } } int numChildren = start.numItems() + 1; for (int childIndex = 0; childIndex < numChildren; childIndex++) { checkTree(start.getChild(childIndex)); } } } /** * Basic storage element for the 2-4 Tree * * @author Dr. Gallagher * @version 1.0 * Created 2 Mar 2001 * Description: The basic node for a 2-4 tree. Contains an array of Items, * an array of references to children TFNodes, a pointer to a parent TFNode, * and a count of how many Items are stored in the node. */ class TFNode { private static final int MAX_ITEMS = 3; private int numItems = 0; private TFNode nodeParent; private TFNode[] nodeChildren; private Object[] nodeItems; public TFNode() { // make them one bigger than needed, so can handle oversize nodes // during inserts nodeChildren = new TFNode[MAX_ITEMS + 2]; nodeItems = new Object[MAX_ITEMS + 1]; } public int numItems() { return numItems; } public int maxItems() { return MAX_ITEMS; } public TFNode getParent() { return nodeParent; } public void setParent(TFNode parent) { nodeParent = parent; } public Object getItem(int index) { if ((index < 0) || (index > (numItems - 1))) throw new TFNodeException(); return nodeItems[index]; } // adds, but does not extend array; so it overwrites anything there public void addItem(int index, Object data) { // always add at end+1; check that you are within array if ((index < 0) || (index > numItems) || (index > MAX_ITEMS)) throw new TFNodeException(); nodeItems[index] = data; numItems++; } // this function inserts an item into the node, and adjusts into child // pointers to add the proper corresponding pointer public void insertItem(int index, Object data) { if ((index < 0) || (index > numItems) || (index > MAX_ITEMS)) throw new TFNodeException(); // adjust Items for (int ind = numItems; ind > index; ind--) { nodeItems[ind] = nodeItems[ind - 1]; } // insert new data into hole made nodeItems[index] = data; // adjust children pointers; if inserting into index=1, we make // pointers 1 and 2 to point to 1; this is because whoever called // this function will fix one of them later; index 0 doesn't change; // pointer 3 becomes pointer 2; pointer 4 becomes 3, etc. for (int ind = numItems + 1; ind > index; ind--) { nodeChildren[ind] = nodeChildren[ind - 1]; } numItems++; } // this method removes item, and shrinks array public Object removeItem(int index) { if ((index < 0) || (index > (numItems - 1))) throw new TFNodeException(); Object removedItem = nodeItems[index]; for (int ind = index; ind < numItems - 1; ind++) { nodeItems[ind] = nodeItems[ind + 1]; } nodeItems[numItems - 1] = null; // fix children pointers also // typically, you wouldn't expect to do a removeItem unless // children are null, because removal of an item will mess up the // pointers; however, here we will simply delete the child to the // left of the removed item; i.e., the child with same index for (int ind = index; ind < numItems; ind++) { nodeChildren[ind] = nodeChildren[ind + 1]; } nodeChildren[numItems] = null; numItems--; return removedItem; } // this method removes item, but does not shrink array public Object deleteItem(int index) { if ((index < 0) || (index > (numItems - 1))) throw new TFNodeException(); Object removedItem = nodeItems[index]; nodeItems[index] = null; numItems--; return removedItem; } // replaces Item at index with newItem, returning the old Item public Object replaceItem(int index, Object newItem) { if ((index < 0) || (index > (numItems - 1))) throw new TFNodeException(); Object returnItem = nodeItems[index]; nodeItems[index] = newItem; return returnItem; } public TFNode getChild(int index) { if ((index < 0) || (index > (MAX_ITEMS + 1))) throw new TFNodeException(); return nodeChildren[index]; } public void setChild(int index, TFNode child) { if ((index < 0) || (index > (MAX_ITEMS + 1))) throw new TFNodeException(); nodeChildren[index] = child; } } class TFNodeException extends RuntimeException { public TFNodeException() { super("Problem with TFNode"); } public TFNodeException(String errorMsg) { super(errorMsg); } } interface Dictionary { public int size(); public boolean isEmpty(); public Object findElement(Object key) throws ElementNotFoundException; public void insertElement(Object key, Object element); public Object removeElement(Object key) throws ElementNotFoundException; } class ElementNotFoundException extends RuntimeException { public ElementNotFoundException() { } } class Item { private Object itemKey; private Object itemElement; public Item() { this(null, null); } public Item(Object key, Object element) { itemKey = key; itemElement = element; } public Object key() { return itemKey; } public void setKey(Object key) { itemKey = key; } public Object element() { return itemElement; } public void setElement(Object element) { itemElement = element; } } interface Comparator { public boolean isLessThan(Object obj1, Object obj2); public boolean isLessThanOrEqualTo(Object obj1, Object obj2); public boolean isGreaterThan(Object obj1, Object obj2); public boolean isGreaterThanOrEqualTo(Object obj1, Object obj2); public boolean isEqual(Object obj1, Object obj2); public boolean isComparable(Object obj); } class IntegerComparator implements Comparator { public IntegerComparator() { } public boolean isLessThan(Object obj1, Object obj2) { Integer myInt1; Integer myInt2; try { myInt1 = (Integer) obj1; myInt2 = (Integer) obj2; } catch (ClassCastException exc) { throw new InvalidIntegerException("Object not an integer"); } return (myInt1.intValue() < myInt2.intValue()); } public boolean isLessThanOrEqualTo(Object obj1, Object obj2) { return (!isLessThan(obj2, obj1)); } public boolean isGreaterThan(Object obj1, Object obj2) { return (isLessThan(obj2, obj1)); } public boolean isGreaterThanOrEqualTo(Object obj1, Object obj2) { return (!isLessThan(obj1, obj2)); } public boolean isEqual(Object obj1, Object obj2) { return ((!isLessThan(obj1, obj2)) && (!isLessThan(obj2, obj1))); } public boolean isComparable(Object obj) { try { Integer myInt = (Integer) obj; return true; } catch (ClassCastException exc) { return false; } } } class InvalidIntegerException extends RuntimeException { public InvalidIntegerException(String errorMsg) { super(errorMsg); } }