123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /**
- * SearchHeap:
- * Implementation of a Search Heap of type T.
- *
- * Designed and written by Jonathan E. Landrum.
- *
- * Copyright (c) 2014-2015 Jonathan E. Landrum. All Rights Reserved.
- */
- // Warnings are suppressed for easier compilation
- @SuppressWarnings("unchecked")
- public class SearchHeap<T> {
- // Root element
- private Node<T> root = new Node<T>();
-
- // Insertion point initially set to root
- private Node<T> ins = root;
-
- // Children and level counts
- private int numLevels = -1;
-
- /*
- * Constructors
- */
- public SearchHeap() { }
- public SearchHeap(Node<T> r) {
- root = r;
- numLevels = 0;
- }
-
- /*
- * Getters
- */
- public int getNumLevels() { return numLevels; }
- public int getNumElements() { return root.getNumElements(); }
- public T getMin() { return root.getMin(); }
- public T getMax() { return root.getMax(); }
- /*
- * getNthMin():
- * This method returns the nth minimum element in the heap.
- *
- * Parameter:
- * int n - The order of the element to be returned.
- *
- * Note:
- * This function expects a natural number for input. Non-
- * natural input will throw an exception. An input of "1" will
- * return the smallest element in the collection, functionally
- * equivalent to calling getMin().
- */
- public T getNthMin(int n) {
- // Define a current node that initially points to root
- Node<T> current = root;
-
- // Short circuit for erroneous input
- if (n > current.getNumElements() || n < 1) {
- throw new IndexOutOfBoundsException(n);
- }
-
- do {
- // Check if we're at the correct node
- if (n == 1) { return current.getMin(); }
- if (n - current.getNumElements() == 0) {
- if (current.hasMax()) {
- return current.getMax();
- } else {
- // We only get here if the algorithm selects this node,
- // but it shouldn't have
- throw new UnknownErrorException();
- }
- }
-
- // Recur through the tree to find the correct node
- if ((current.hasLeftChild()) &&
- (n <= current.getLeftChild().getNumElements() + 1)) {
- /*
- * This block says our target is not current's min
- * (the +1 part), but our target is in current's left subtree
- * (the current.getLeftChild().getNumElements() part).
- */
-
- // Subtract 1 from n to represent passing up current.getMin() as an option
- --n;
-
- // Change what current points to
- current = current.getLeftChild();
- } else if (current.hasRightChild()) {
- /*
- * This block says our target is in current's right subtree.
- */
-
- // Subtract the total number of elements in the left subtree and middle subtree + 1 from n
- // to represent passing up the left and middle subtrees as an option
- n = n - current.getLeftChild().getNumElements() - 1;
-
- // Change what current points to
- current = current.getRightChild();
- } else {
- /*
- * We only get here if current has no children (is a leaf),
- * but n > 2, an obvious error, given the checks at the
- * beginning of the loop
- */
- throw new UnknownErrorException();
- }
- } while (n > 0);
-
- // We only get here if something goes completely awry
- throw new UnknownErrorException();
- }
- /*
- * getNthMax():
- * This method returns the nth maximum element in the heap.
- *
- * Parameter:
- * int n - The order of the element to be returned.
- *
- * Note:
- * This function expects a natural number for input. Non-
- * natural input will throw an exception. An input of "1" will
- * return the largest element in the collection, functionally
- * equivalent to calling getMax().
- */
- public T getNthMax(int n) {
- // Define a current node that initially points to root
- Node<T> current = root;
-
- // Short circuit for erroneous input
- if (n > current.getNumElements() || n < 1) { throw new IndexOutOfBoundsException(n); }
-
- do {
- // Check if we're at the correct node
- if (n == 1) { return current.getMax(); }
- if (n - current.getNumElements() == 0) {
- if (current.hasMin()) {
- return current.getMin();
- } else {
- // We only get here if the algorithm selects this node, but it shouldn't have
- throw new UnknownErrorException();
- }
- }
-
- // Recur through the tree to find the correct node
- if ((current.hasRightChild()) && (n <= current.getRightChild().getNumElements() + 1)) {
- /*
- * This block says our target is not current's max (the +1 part),
- * but our target is in current's right subtree (the current.getRightChild().getNumElements() part).
- */
-
- // Subtract 1 from n to represent passing up current.getMax() as an option
- --n;
-
- // Change what current points to
- current = current.getRightChild();
- } else if (current.hasMidChild()) {
- // We have to be careful here, because we can't assume current has a right child
- // in the same way we could assume current has a left child in getNthMin().
- if ((current.hasRightChild()) && (n <= current.getRightChild().getNumElements() + current.getMidChild().getNumElements() + 1)) {
- /*
- * This block says our target is not current's max (the +1 part),
- * and our target is not in current's right subtree (the current.getRightChild().getNumElements() part),
- * but our target *is* in current's middle subtree (the current.getMidChild().getNumElements() part).
- */
-
- // Subtract the total number of elements in the right subtree + 1 from n
- // to represent passing up current.getMax() as well as current's right subtree as an option
- n = n - current.getRightChild().getNumElements() - 1;
- } else {
- // Otherwise, if current doesn't have a right child, just subtract 1 to represent passing up current.getMax().
- --n;
- }
-
- // Change what current points to
- current = current.getMidChild();
- } else if (current.hasLeftChild()) {
- /*
- * This block says we've exhausted our options, and our target has to be in current's left subtree.
- */
- if (current.hasMidChild()) {
- // We have to be careful here, too, just as above
- if (current.hasRightChild()) {
- // Subtract the total number of elements in the right and middle subtrees + 1 from n
- // to represent passing up current.getMax() as well as current's right and middle subtrees as options
- n = n - current.getRightChild().getNumElements() - current.getMidChild().getNumElements() - 1;
- } else {
- // Otherwise, if current doesn't have a right child, subtract the total number of elements
- // from the middle subtree + 1 to represent passing up the middle subtree and current.getMax().
- n = n - current.getMidChild().getNumElements() - 1;
- }
- // Otherwise, if there is no middle child and no right child,
- // just subtract 1 to represent passing up current.getMax().
- --n;
- }
-
- // Change what current points to
- current = current.getLeftChild();
- } else {
- /*
- * We only get here if current has no children (is a leaf), but n != 1 and n != 2,
- * an obvious error, given the checks at the beginning of the loop
- */
- throw new UnknownErrorException();
- }
- } while (n > 0);
-
- // We only get here if something goes completely awry
- throw new UnknownErrorException();
- }
-
- /*
- * insert():
- * This method adds a new element to the heap.
- *
- * Calls:
- * reheap()
- *
- * //////////////////\\\\\\\\\\\\\\\\\\
- * TO DO: Implement This
- * \\\\\\\\\\\\\\\\\\//////////////////
- *
- * Parameter:
- * T element - The element to be inserted into the heap.
- *
- * Note :
- * The structure of this method forms a natural less-than-
- * or-equal-to relation. As the collection has a least element,
- * it thus forms a total ordering.
- */
- public void insert(T element) {
- // Define a current node that initially references the insertion point
- Node<T> current = ins;
-
- // Insert the element
- if (!current.hasMin()) {
- /*
- * The node is completely empty; insert the element as current's min.
- */
- current.setMin(element);
- } else if (!current.hasMax()) {
- /*
- * The node is partially empty; determine which value goes in which slot.
- */
- if (current.getMin().compareTo(element) > 0) {
- // Current's min is greater than the element, so
- // it becomes max and the element becomes min.
- current.setMax(current.getMin());
- current.setMin(element);
- } else {
- // Current's min is less than or equal to the
- // element, so the element becomes the max.
- current.setMax(element);
- }
- } else {
- /*
- * The insertion point is full. Create a new node to hold
- * the element, and determine where to put the new node.
- */
- Node<T> newNode = new Node<T>(element);
-
- // Check to see where the new node goes.
- if (current.hasParent()) {
- /*
- * Avoids null pointer exceptions when current points to root.
- */
- if (current.isLeftChild()) {
- // Current is a left child, so newNode becomes the middle child.
- // Point the three nodes at each other.
- current.setRightSibling(newNode);
- current.getParent().setMidChild(newNode);
- newNode.setLeftSibling(current);
- newNode.setParent(current.getParent());
- } else if (current.isMidChild()) {
- // Current is a middle child, so newNode becomes the right child.
- // Point the three nodes at each other.
- current.setRightSibling(newNode);
- current.getParent().setRightChild(newNode);
- newNode.setLeftSibling(current);
- newNode.setParent(current.getParent());
- } else {
- /*
- * Current is a right child. Determine if we need to
- * move to a right subtree or create a new level.
- */
-
- // Iterate current up the tree until a right sibling is found. If no right sibling
- // is found, current is an external node, and a new level should be created.
- while (!current.hasRightSibling()) {
- if (current.hasParent()) {
- // Move current to the parent node.
- current = current.getParent();
-
- // Check to see if the new current has a right sibling.
- if (current.hasRightSibling()) {
- // Move current into adjacent subtree and terminate the loop.
- current = current.getRightSibling();
- break;
- }
- } else {
- // Current is the root node. Increment the
- // number of levels and terminate the loop.
- ++numLevels;
- break;
- }
- }
-
- // Iterate through the tree until the bottom row is reached.
- while (current.hasLeftChild()) {
- current = current.getLeftChild();
- }
-
- // Point current and the new node at each other.
- current.setLeftChild(newNode);
- newNode.setParent(current);
-
- }
- } else {
- /*
- * This case only happens when the insertion point is the root.
- */
-
- // Point the two nodes at each other.
- current.setLeftChild(newNode);
- newNode.setParent(current);
- }
-
- // Point ins at the new node.
- ins = newNode;
- }
- }
- }
|