public T dequeueMin() {
        /* Cache the value to return; this also checks for an empty heap. */
        T toReturn = min();

        /* If this is a singleton heap, throw out the last node.  We're done. */
        if (size() == 1) {
            elems.remove(1);
            --numElems;
            return toReturn;
        }

        /* Move the min element from the last node to fill the
         * place of the element we just removed.  This might
         * empty the last node, in which case we remove it.
         */
        Node<T> lastNode = elems.get(elems.size() - 1);
        elems.get(1).low = lastNode.low;

        /* Odd number of elements; remove the last node. */
        if (size() % 2 == 1)
            elems.remove(elems.size() - 1);
        /* Otherwise, scoot the high element down to the
         * low slot.
         */
        else {
            lastNode.low = lastNode.high;
            lastNode.high = null;
        }
        --numElems;

        /* Continously do a bubble-down, at each point ensuring that the
         * endpoints of the current node are correct.
         */
        int index = 1;
        Node<T> currNode = elems.get(index);

        while (true) {
            /* If we have no children, we're done. */
            if (index * 2 >= elems.size())
                break;
           
            /* Otherwise, we either have one child or two children.  Check which case we're in. */
            int childToCompareTo; // Which child we'll end up testing

            /* If we have two children, compare the two and store the smaller one. */
            if (index * 2 + 1 < elems.size())
                childToCompareTo = (comparator.compare(elems.get(index * 2).low, elems.get(2 * index + 1).low) < 0? index * 2 : index * 2 + 1);
            /* Otherwise, only compare to the one child we have. */
            else
                childToCompareTo = index * 2;

            /* If we are smaller than the child, we're done. */
            Node<T> child = elems.get(childToCompareTo);
            if (comparator.compare(currNode.low, child.low) < 0)
                break;

            /* Otherwise, swap down and continue. */
            T temp = child.low;
            child.low = currNode.low;
            currNode.low = temp;

            /* Check that the child's endpoints are ordered correctly.  When doing
             * so, check that the high field isn't null, since if we hit the very
             * last node we don't want to compare against null.
             */
            if (child.high != null && comparator.compare(child.low, child.high) > 0) {
                /* Swap the two. */
                temp = child.low;
                child.low = child.high;
                child.high = temp;
            }

            /* Update position and node. */
            index = childToCompareTo;
            currNode = child;
        }

        /* All done!  Return the proper value. */
        return toReturn;
    }