/** * Copyright 2013 Akshay Jain (akshay.jain.7983@gmail.com) * * This file is part of PriorityDeque. * * PriorityDeque is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * PriorityDeque is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with PriorityDeque. If not, see <http://www.gnu.org/licenses/>. */ package com.util; import java.io.Serializable; import java.util.AbstractQueue; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.ConcurrentModificationException; import java.util.Deque; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.SortedSet; /** * @author Akshay Jain * */ public class PriorityDeque<E> extends AbstractQueue<E> implements Deque<E>, Serializable { private static final long serialVersionUID = -5410497035045299533L; private static final int DEFAULT_INITIAL_CAPACITY = 11; private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private static enum Level { MIN, MAX }; private transient Object[] deque; private final Comparator<? super E> comparator; private int size = 0; private transient int modCount = 0; public PriorityDeque() { this(DEFAULT_INITIAL_CAPACITY, null); } public PriorityDeque(int initialCapacity) { this(initialCapacity, null); } public PriorityDeque(int initialCapacity, Comparator<? super E> comparator) { // Note: This restriction of at least one is not actually needed, // but continues for 1.5 compatibility if (initialCapacity < 1) throw new IllegalArgumentException(); this.deque = new Object[initialCapacity]; this.comparator = comparator; } @SuppressWarnings("unchecked") public PriorityDeque(Collection<? extends E> c) { if (c instanceof SortedSet<?>) { SortedSet<? extends E> ss = (SortedSet<? extends E>) c; this.comparator = (Comparator<? super E>) ss.comparator(); addAll(ss); } else if (c instanceof PriorityDeque<?>) { PriorityDeque<? extends E> pq = (PriorityDeque<? extends E>) c; this.comparator = (Comparator<? super E>) pq.comparator(); initFromPriorityDeque(pq); } else { this.comparator = null; addAll(c); } } @SuppressWarnings("unchecked") public PriorityDeque(PriorityDeque<? extends E> c) { this.comparator = (Comparator<? super E>) c.comparator(); initFromPriorityDeque(c); } @SuppressWarnings("unchecked") public PriorityDeque(SortedSet<? extends E> c) { this.comparator = (Comparator<? super E>) c.comparator(); addAll(c); } private void initFromPriorityDeque(PriorityDeque<? extends E> c) { if (c.getClass() == PriorityDeque.class) { deque = c.toArray(); size = c.size(); } else { addAll(c); } } @Override public void addFirst(E e) { add(e); } @Override public void addLast(E e) { add(e); } @Override public boolean offerFirst(E e) { return offer(e); } @Override public boolean offerLast(E e) { return offer(e); } public E remove() { E x = poll(); if (x != null) return x; else throw new NoSuchElementException(); } @Override public E removeFirst() { E x = pollFirst(); if (x != null) return x; else throw new NoSuchElementException(); } @Override public E removeLast() { E x = pollLast(); if (x != null) return x; else throw new NoSuchElementException(); } @Override public E pollFirst() { modCount++; return removeAt(0); } @Override public E pollLast() { modCount++; int indexMax = indexOfLargerChild(deque, size, 0, comparator); int indexRemove = indexMax>0?indexMax:0; return removeAt(indexRemove); } @Override public E getFirst() { E x = peekFirst(); if (x != null) return x; else throw new NoSuchElementException(); } @Override public E getLast() { E x = peekLast(); if (x != null) return x; else throw new NoSuchElementException(); } @Override @SuppressWarnings("unchecked") public E peekFirst() { if (size > 0) { return (E) deque[0]; } else return null; } @Override @SuppressWarnings("unchecked") public E peekLast() { E result = null; if (size > 0) { int indexMax = indexOfLargerChild(deque, size, 0, comparator); int indexPeek = indexMax>0?indexMax:0; result = (E) deque[indexPeek]; } return result; } @Override public boolean removeFirstOccurrence(Object o) { int firstIndex = -1; for (int count = 0; count < size; count++) { if (deque[count].equals(o)) { firstIndex = count; break; } } if (firstIndex >= 0) { modCount++; removeAt(firstIndex); return true; } else return false; } @Override public boolean removeLastOccurrence(Object o) { int lastIndex = -1; for (int count = size - 1; count >= 0; count--) { if (deque[count].equals(o)) { lastIndex = count; break; } } if (lastIndex >= 0) { modCount++; removeAt(lastIndex); return true; } else return false; } @Override public boolean offer(E element) { modCount++; if (element == null) throw new NullPointerException(); int index = size; if (index >= deque.length) grow(index + 1); size = index + 1; if (index == 0) deque[0] = element; else { deque[index] = element; if (comparator == null) bubbleUp(deque, size, index); else bubbleUpComparator(deque, size, index, comparator); } return true; } @Override public E poll() { return pollFirst(); } @Override public E peek() { return peekFirst(); } @Override public void push(E e) { throw new UnsupportedOperationException("Cannot use a priority deque as a stack"); } @Override public E pop() { throw new UnsupportedOperationException("Cannot use a priority deque as a stack"); } private static int indexOf(Object o, Object[] deque, int size) { if (o != null) { for (int i = 0; i < size; i++) if (o.equals(deque[i])) return i; } return -1; } /** * Removes a single instance of the specified element from this queue, if it * is present. More formally, removes an element {@code e} such that * {@code o.equals(e)}, if this queue contains one or more such elements. * Returns {@code true} if and only if this queue contained the specified * element (or equivalently, if this queue changed as a result of the call). * * @param o * element to be removed from this queue, if present * @return {@code true} if this queue changed as a result of the call */ public boolean remove(Object o) { int i = indexOf(o, deque, size); if (i == -1) return false; else { modCount++; removeAt(i); return true; } } /** * Returns {@code true} if this queue contains the specified element. More * formally, returns {@code true} if and only if this queue contains at * least one element {@code e} such that {@code o.equals(e)}. * * @param o * object to be checked for containment in this queue * @return {@code true} if this queue contains the specified element */ public boolean contains(Object o) { return indexOf(o, deque, size) != -1; } /** * Returns an array containing all of the elements in this queue. The * elements are in no particular order. * * <p> * The returned array will be "safe" in that no references to it are * maintained by this queue. (In other words, this method must allocate a * new array). The caller is thus free to modify the returned array. * * <p> * This method acts as bridge between array-based and collection-based APIs. * * @return an array containing all of the elements in this queue */ public Object[] toArray() { return Arrays.copyOf(deque, size); } /** * Returns an array containing all of the elements in this queue; the * runtime type of the returned array is that of the specified array. The * returned array elements are in no particular order. If the queue fits in * the specified array, it is returned therein. Otherwise, a new array is * allocated with the runtime type of the specified array and the size of * this queue. * * <p> * If the queue fits in the specified array with room to spare (i.e., the * array has more elements than the queue), the element in the array * immediately following the end of the collection is set to {@code null}. * * <p> * Like the {@link #toArray()} method, this method acts as bridge between * array-based and collection-based APIs. Further, this method allows * precise control over the runtime type of the output array, and may, under * certain circumstances, be used to save allocation costs. * * <p> * Suppose <tt>x</tt> is a queue known to contain only strings. The * following code can be used to dump the queue into a newly allocated array * of <tt>String</tt>: * * <pre> * String[] y = x.toArray(new String[0]); * </pre> * * Note that <tt>toArray(new Object[0])</tt> is identical in function to * <tt>toArray()</tt>. * * @param a * the array into which the elements of the queue are to be * stored, if it is big enough; otherwise, a new array of the * same runtime type is allocated for this purpose. * @return an array containing all of the elements in this queue * @throws ArrayStoreException * if the runtime type of the specified array is not a supertype * of the runtime type of every element in this queue * @throws NullPointerException * if the specified array is null */ @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { if (a.length < size) // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(deque, size, a.getClass()); System.arraycopy(deque, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } @SuppressWarnings("unchecked") private boolean removeAtIter(int index, boolean desc) { if(!desc) { if (index < size - 1) { E moved = (E) deque[size - 1]; modCount++; removeAt(index); if (moved == deque[index]) return true; } } else { if(index >= 0) { removeAt(index); } } return false; } @Override public Iterator<E> descendingIterator() { return new Itr(true); } @Override public Iterator<E> iterator() { return new Itr(false); } private final class Itr implements Iterator<E> { private boolean desc = false; /** * Index (into queue array) of element to be returned by subsequent call * to next. */ private int cursor = 0; /** * Index of element returned by most recent call to next, unless that * element came from the forgetMeNot list. Set to -1 if element is * deleted by a call to remove. */ private int lastRet = -1; /** * The modCount value that the iterator believes that the backing Queue * should have. If this expectation is violated, the iterator has * detected concurrent modification. */ private int expectedModCount = modCount; private Itr(boolean desc) { this.desc = desc; if (desc) cursor = size - 1; } public boolean hasNext() { return (!desc && cursor < size) || (desc && cursor >= 0); } public E next() { if (expectedModCount != modCount) throw new ConcurrentModificationException(); if (!desc) return nextAsc(); if (desc) return nextDesc(); throw new NoSuchElementException(); } public void remove() { if (expectedModCount != modCount) throw new ConcurrentModificationException(); if (lastRet != -1) { boolean decrementCounter = PriorityDeque.this.removeAtIter(lastRet, desc); lastRet = -1; if (decrementCounter) { cursor--; } } else { throw new IllegalStateException(); } expectedModCount = modCount; } @SuppressWarnings("unchecked") private E nextAsc() { if (cursor < size) return (E) PriorityDeque.this.deque[lastRet = cursor++]; throw new NoSuchElementException(); } @SuppressWarnings("unchecked") private E nextDesc() { if (cursor >= 0) return (E) PriorityDeque.this.deque[lastRet = cursor--]; throw new NoSuchElementException(); } } @Override public int size() { return size; } private void grow(int minCapacity) { int oldCapacity = deque.length; // Double size if small; else grow by 50% int newCapacity = oldCapacity + ((oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1)); // overflow-conscious code if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); deque = Arrays.copyOf(deque, newCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } public void clear() { modCount++; for (int i = 0; i < size; i++) deque[i] = null; size = 0; } /** * Returns the comparator used to order the elements in this queue, or * {@code null} if this queue is sorted according to the * {@linkplain Comparable natural ordering} of its elements. * * @return the comparator used to order this queue, or {@code null} if this * queue is sorted according to the natural ordering of its elements */ public Comparator<? super E> comparator() { return comparator; } /** * Saves the state of the instance to a stream (that is, serializes it). * * @serialData The length of the array backing the instance is emitted * (int), followed by all of its elements (each an * {@code Object}) in the proper order. * @param s * the stream */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out element count, and any hidden stuff s.defaultWriteObject(); // Write out array length, for compatibility with 1.5 version s.writeInt(Math.max(2, size + 1)); // Write out all elements in the "proper order". for (int i = 0; i < size; i++) s.writeObject(deque[i]); } /** * Reconstitutes the {@code PriorityQueue} instance from a stream (that is, * deserializes it). * * @param s * the stream */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in size, and any hidden stuff s.defaultReadObject(); // Read in (and discard) array length s.readInt(); deque = new Object[size]; // Read in all elements. for (int i = 0; i < size; i++) deque[i] = s.readObject(); } // min-max heap implementation @SuppressWarnings("unchecked") private E removeAt(int index) { if (index < 0 || index >= size) throw new IllegalArgumentException(); if (size > 0) { E obj = (E) deque[index]; size--; if (size > 0) { deque[index] = deque[size]; deque[size] = null; trickleDown(deque, size, index, comparator); } else deque[index] = null; return obj; } return null; } @SuppressWarnings("unchecked") private static <T> void bubbleUp(final Object[] deque, final int size, int index) { int parentIndex = getParentIndex(index); if (Level.MIN.equals(getLevel(size, index))) { if (index > 0 && ((Comparable<? super T>) deque[index]).compareTo((T) deque[parentIndex]) > 0) { swap(deque, size, index, parentIndex); bubbleUpMax(deque, size, parentIndex); } else { bubbleUpMin(deque, size, index); } } else { if (index > 0 && ((Comparable<? super T>) deque[index]).compareTo((T) deque[parentIndex]) < 1) { swap(deque, size, index, parentIndex); bubbleUpMin(deque, size, parentIndex); } else { bubbleUpMax(deque, size, index); } } } @SuppressWarnings("unchecked") private static <T> void bubbleUpComparator(final Object[] deque, final int size, int index, final Comparator<? super T> comparator) { int parentIndex = getParentIndex(index); if (Level.MIN.equals(getLevel(size, index))) { if (index > 0 && comparator.compare((T) deque[index], (T) deque[parentIndex]) > 0) { swap(deque, size, index, parentIndex); bubbleUpMaxComparator(deque, size, parentIndex, comparator); } else { bubbleUpMinComparator(deque, size, index, comparator); } } else { if (index > 0 && comparator.compare((T) deque[index], (T) deque[parentIndex]) < 1) { swap(deque, size, index, parentIndex); bubbleUpMinComparator(deque, size, parentIndex, comparator); } else { bubbleUpMaxComparator(deque, size, index, comparator); } } } @SuppressWarnings("unchecked") private static <T> void bubbleUpMax(final Object[] deque, final int size, int index) { int grandParentIndex = getParentIndex(getParentIndex(index)); while (grandParentIndex >= 0 && ((Comparable<? super T>) deque[index]).compareTo((T) deque[grandParentIndex]) > 0) { swap(deque, size, index, grandParentIndex); index = grandParentIndex; grandParentIndex = getParentIndex(getParentIndex(grandParentIndex)); } } @SuppressWarnings("unchecked") private static <T> void bubbleUpMaxComparator(final Object[] deque, final int size, int index, final Comparator<? super T> comparator) { int grandParentIndex = getParentIndex(getParentIndex(index)); while (grandParentIndex >= 0 && comparator.compare((T) deque[index], (T) deque[grandParentIndex]) > 0) { swap(deque, size, index, grandParentIndex); index = grandParentIndex; grandParentIndex = getParentIndex(getParentIndex(grandParentIndex)); } } @SuppressWarnings("unchecked") private static <T> void bubbleUpMin(final Object[] deque, final int size, int index) { int grandParentIndex = getParentIndex(getParentIndex(index)); while (grandParentIndex >= 0 && ((Comparable<? super T>) deque[index]).compareTo((T) deque[grandParentIndex]) < 1) { swap(deque, size, index, grandParentIndex); index = grandParentIndex; grandParentIndex = getParentIndex(getParentIndex(grandParentIndex)); } } @SuppressWarnings("unchecked") private static <T> void bubbleUpMinComparator(final Object[] deque, final int size, int index, final Comparator<? super T> comparator) { int grandParentIndex = getParentIndex(getParentIndex(index)); while (grandParentIndex >= 0 && comparator.compare((T) deque[index], (T) deque[grandParentIndex]) < 1) { swap(deque, size, index, grandParentIndex); index = grandParentIndex; grandParentIndex = getParentIndex(getParentIndex(grandParentIndex)); } } private static <T> void trickleDown(final Object[] deque, final int size, int index, final Comparator<? super T> comparator) { if (Level.MIN.equals(getLevel(size, index))) { if (comparator == null) trickleDownMin(deque, size, index); else trickleDownMinComparator(deque, size, index, comparator); } else { if (comparator == null) trickleDownMax(deque, size, index); else trickleDownMaxComparator(deque, size, index, comparator); } } @SuppressWarnings("unchecked") private static <T> void trickleDownMin(final Object[] deque, final int size, int index) { while (index >= 0 && (isLeftChildPresent(deque, size, index) || isRightChildPresent(deque, size, index))) { int iSmallestGc = indexOfSmallestGrandChild(deque, size, index, null); int iSmallestCh = indexOfSmallerChild(deque, size, index, null); if (iSmallestGc > 0 && ((Comparable<? super T>) deque[iSmallestGc]).compareTo((T) deque[index]) < 1) { swap(deque, size, index, iSmallestGc); int parent = getParentIndex(iSmallestGc); if (((Comparable<? super T>) deque[iSmallestGc]).compareTo((T) deque[parent]) > 0) swap(deque, size, iSmallestGc, parent); } if (iSmallestCh > 0 && ((Comparable<? super T>) deque[iSmallestCh]).compareTo((T) deque[index]) < 1) swap(deque, size, index, iSmallestCh); index = iSmallestGc; } } @SuppressWarnings("unchecked") private static <T> void trickleDownMinComparator(final Object[] deque, final int size, int index, final Comparator<? super T> comparator) { while (index >= 0 && (isLeftChildPresent(deque, size, index) || isRightChildPresent(deque, size, index))) { int iSmallestGc = indexOfSmallestGrandChild(deque, size, index, comparator); int iSmallestCh = indexOfSmallerChild(deque, size, index, comparator); if (iSmallestGc > 0 && comparator.compare((T) deque[iSmallestGc], (T) deque[index]) < 1) { swap(deque, size, index, iSmallestGc); int parent = getParentIndex(iSmallestGc); if (comparator.compare((T) deque[iSmallestGc], (T) deque[parent]) > 0) swap(deque, size, iSmallestGc, parent); } if (iSmallestCh > 0 && comparator.compare((T) deque[iSmallestCh], (T) deque[index]) < 1) swap(deque, size, index, iSmallestCh); index = iSmallestGc; } } @SuppressWarnings("unchecked") private static <T> void trickleDownMax(final Object[] deque, final int size, int index) { while (index >= 0 && (isLeftChildPresent(deque, size, index) || isRightChildPresent(deque, size, index))) { int iLargestGc = indexOfLargestGrandChild(deque, size, index, null); int iLargestCh = indexOfLargerChild(deque, size, index, null); if (iLargestGc > 0 && ((Comparable<? super T>) deque[iLargestGc]).compareTo((T) deque[index]) > 0) { swap(deque, size, index, iLargestGc); int parent = getParentIndex(iLargestGc); if (((Comparable<? super T>) deque[iLargestGc]).compareTo((T) deque[parent]) < 1) swap(deque, size, iLargestGc, parent); } if (iLargestCh > 0 && ((Comparable<? super T>) deque[iLargestCh]).compareTo((T) deque[index]) > 0) swap(deque, size, index, iLargestCh); index = iLargestGc; } } @SuppressWarnings("unchecked") private static <T> void trickleDownMaxComparator(final Object[] deque, final int size, int index, final Comparator<? super T> comparator) { while (index >= 0 && (isLeftChildPresent(deque, size, index) || isRightChildPresent(deque, size, index))) { int iLargestGc = indexOfLargestGrandChild(deque, size, index, comparator); int iLargestCh = indexOfLargerChild(deque, size, index, comparator); if (iLargestGc > 0 && comparator.compare((T) deque[iLargestGc], (T) deque[index]) > 0) { swap(deque, size, index, iLargestGc); int parent = getParentIndex(iLargestGc); if (comparator.compare((T) deque[iLargestGc], (T) deque[parent]) < 1) swap(deque, size, iLargestGc, parent); } if (iLargestCh > 0 && comparator.compare((T) deque[iLargestCh], (T) deque[index]) > 0) swap(deque, size, index, iLargestCh); index = iLargestGc; } } private static Level getLevel(final int size, int index) { int noOfElements = 0; int depth = 0; for (; depth < size; depth++) { noOfElements += Math.pow(2, depth); if ((index - noOfElements) < 0) break; } return depth % 2 == 0 ? Level.MIN : Level.MAX; } private static boolean isLeftChildPresent(final Object[] deque, final int size, final int index) { int leftChildIndex = getLeftChildIndex(index); return (leftChildIndex < size && deque[leftChildIndex] != null); } private static boolean isRightChildPresent(final Object[] deque, final int size, final int index) { int rightChildIndex = getRightChildIndex(index); return (rightChildIndex < size && deque[rightChildIndex] != null); } private static int getParentIndex(int childIndex) { return childIndex > 0 ? (int) ((childIndex - 1) / 2) : -1; } private static int getLeftChildIndex(int parentIndex) { return (int) (2 * parentIndex + 1); } private static int getRightChildIndex(int parentIndex) { return (int) (2 * (parentIndex + 1)); } private static Object[][] getChildren(final Object[] deque, final int size, int index) { Object[][] children = new Object[2][2]; int leftChildIndex = getLeftChildIndex(index); int rightChildIndex = getRightChildIndex(index); if (isLeftChildPresent(deque, size, index)) { children[0][0] = deque[leftChildIndex]; children[1][0] = leftChildIndex; } if (isRightChildPresent(deque, size, index)) { children[0][1] = deque[rightChildIndex]; children[1][1] = rightChildIndex; } return children; } @SuppressWarnings("unchecked") private static <T> int indexOfSmallerChild(final Object[] deque, final int size, int index, final Comparator<? super T> comparator) { Object[][] children = getChildren(deque, size, index); if (children[0][0] == null && children[0][1] == null) return -1; else if (children[0][0] == null) return (int) children[1][1]; else if (children[0][1] == null) return (int) children[1][0]; else if (comparator == null) { if (((Comparable<? super T>) children[0][0]).compareTo((T) children[0][1]) < 1) return (int) children[1][0]; else return (int) children[1][1]; } else { if (comparator.compare((T) children[0][0], (T) children[0][1]) < 1) return (int) children[1][0]; else return (int) children[1][1]; } } @SuppressWarnings("unchecked") private static <T> int indexOfLargerChild(final Object[] deque, final int size, int index, final Comparator<? super T> comparator) { Object[][] children = getChildren(deque, size, index); if (children[0][0] == null && children[0][1] == null) return -1; else if (children[0][0] == null) return (int) children[1][1]; else if (children[0][1] == null) return (int) children[1][0]; else if (comparator == null) { if (((Comparable<? super T>) children[0][0]).compareTo((T) children[0][1]) > 0) return (int) children[1][0]; else return (int) children[1][1]; } else { if (comparator.compare((T) children[0][0], (T) children[0][1]) > 0) return (int) children[1][0]; else return (int) children[1][1]; } } private static Object[][] getGrandChildren(final Object[] deque, final int size, int index) { Object[][] grandChildren = new Object[2][4]; int leftChildIndex = getLeftChildIndex(index); int rightChildIndex = getRightChildIndex(index); int gcll = getLeftChildIndex(leftChildIndex), gclr = getRightChildIndex(leftChildIndex), gcrl = getLeftChildIndex(rightChildIndex), gcrr = getRightChildIndex(rightChildIndex); if (isLeftChildPresent(deque, size, index)) { if (isLeftChildPresent(deque, size, leftChildIndex)) { grandChildren[0][0] = deque[gcll]; grandChildren[1][0] = gcll; } if (isRightChildPresent(deque, size, leftChildIndex)) { grandChildren[0][1] = deque[gclr]; grandChildren[1][1] = gclr; } } if (isRightChildPresent(deque, size, index)) { if (isLeftChildPresent(deque, size, rightChildIndex)) { grandChildren[0][2] = deque[gcrl]; grandChildren[1][2] = gcrl; } if (isRightChildPresent(deque, size, rightChildIndex)) { grandChildren[0][3] = deque[gcrr]; grandChildren[1][3] = gcrr; } } return grandChildren; } @SuppressWarnings("unchecked") private static <T> int indexOfSmallestGrandChild(final Object[] deque, final int size, int index, final Comparator<? super T> comparator) { Object[][] grandChildren = getGrandChildren(deque, size, index); Object smallest = grandChildren[0][0]; Object smallestIndex = grandChildren[1][0]; int count = 1; for (; count < grandChildren[0].length; count++) { if (smallest == null) { smallest = grandChildren[0][count]; smallestIndex = grandChildren[1][count]; } else if (grandChildren[0][count] != null) { if (comparator == null) { if (((Comparable<? super T>) smallest).compareTo((T) grandChildren[0][count]) > 0) { smallest = grandChildren[0][count]; smallestIndex = grandChildren[1][count]; } } else { if (comparator.compare((T) smallest, (T) grandChildren[0][count]) > 0) { smallest = grandChildren[0][count]; smallestIndex = grandChildren[1][count]; } } } } return smallestIndex != null ? (int) smallestIndex : -1; } @SuppressWarnings("unchecked") private static <T> int indexOfLargestGrandChild(final Object[] deque, final int size, int index, final Comparator<? super T> comparator) { Object[][] grandChildren = getGrandChildren(deque, size, index); Object largest = grandChildren[0][0]; Object largestIndex = grandChildren[1][0]; int count = 1; for (; count < grandChildren[0].length; count++) { if (largest == null) { largest = grandChildren[0][count]; largestIndex = grandChildren[1][count]; } else if (grandChildren[0][count] != null) { if (comparator == null) { if (((Comparable<? super T>) largest).compareTo((T) grandChildren[0][count]) < 0) { largest = grandChildren[0][count]; largestIndex = grandChildren[1][count]; } } else { if (comparator.compare((T) largest, (T) grandChildren[0][count]) < 0) { largest = grandChildren[0][count]; largestIndex = grandChildren[1][count]; } } } } return largestIndex != null ? (int) largestIndex : -1; } private static void swap(final Object[] deque, final int size, int index1, int index2) { if (index1 < 0 || index1 >= size || index2 < 0 || index2 >= size) throw new IllegalArgumentException(); Object temp = deque[index1]; deque[index1] = deque[index2]; deque[index2] = temp; temp = null; } }