/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.util; import org.jikesrvm.VM; /** * This class implements a priority queue using the standard * (balanced partially-ordered tree, i.e., "heap") algorithm. * Smaller priority objects are in the front of the queue. */ public class PriorityQueueRVM { /** * the queue, we use elements 1..queue.length */ private PriorityQueueNode[] queue; /** * the number of elements actually in the queue */ private int numElements = 0; protected PriorityQueueRVM() { queue = new PriorityQueueNode[20]; // We don't use element #0 for (int i = 1; i < queue.length; i++) { queue[i] = new PriorityQueueNode(); } } /** * Determines number of elements in the queue * @return number of elements in the queue */ public final synchronized int numElements() { return numElements; } /** * Checks if the queue is empty * @return is the queue empty? */ protected final synchronized boolean isEmpty() { return numElements == 0; } /** * Starting at the position passed, swap with parent until heap condition * is satisfied, i.e., bubble up * @param startingElement the position to start at */ private void reheapify(int startingElement) { int current = startingElement; int parent = numElements / 2; // keep checking parents that violate the magic condition while (parent > 0 && queue[parent].priority < queue[current].priority) { // System.out.println("Parent: "+ parent +", Current: "+ current); // System.out.println("Contents before: "+ this); // exchange parrent and current values PriorityQueueNode tmp = queue[parent]; queue[parent] = queue[current]; queue[current] = tmp; // System.out.println("Contents after: "+ this); // go up 1 level current = parent; parent = parent / 2; } } /** * Insert the object passed with the priority value passed * @param _priority the priority of the inserted object * @param _data the object to insert */ public synchronized void insert(double _priority, Object _data) { numElements++; if (numElements == queue.length) { PriorityQueueNode[] tmp = new PriorityQueueNode[(int) (queue.length * 1.5)]; System.arraycopy(queue, 0, tmp, 0, queue.length); for (int i = queue.length; i < tmp.length; i++) { tmp[i] = new PriorityQueueNode(); } queue = tmp; } queue[numElements].data = _data; queue[numElements].priority = _priority; // re-heapify reheapify(numElements); } /** * Remove and return the front (minimum) object * @return the front (minimum) object or null if the queue is empty. */ public synchronized Object deleteMin() { if (isEmpty()) return null; Object returnValue = queue[1].data; // move the "last" element to the root and reheapify by pushing it down queue[1].priority = queue[numElements].priority; queue[1].data = queue[numElements].data; numElements--; // reheapify!!! int current = 1; // The children live at 2*current and 2*current+1 int child1 = 2 * current; while (child1 <= numElements) { int child2 = 2 * current + 1; // find the smaller of the two children int smaller; if (child2 <= numElements && queue[child2].priority > queue[child1].priority) { smaller = child2; } else { smaller = child1; } if (queue[smaller].priority <= queue[current].priority) { break; } else { // exchange parrent and current values PriorityQueueNode tmp = queue[smaller]; queue[smaller] = queue[current]; queue[current] = tmp; // go down 1 level current = smaller; child1 = 2 * current; } } return returnValue; } /** * Return the priority of front object without removing it * @return the priority of the front object */ public final synchronized double rootValue() { if (VM.VerifyAssertions) VM._assert(!isEmpty()); return queue[1].priority; } /** * Prints the contents of the queue * @return the queue contents */ public synchronized String toString() { final StringBuilder sb = new StringBuilder(" --> "); sb.append("Dumping Queue with "); sb.append(numElements); sb.append(" elements:\n"); if (numElements >= 1) sb.append("\t"); for (int i = 1; i <= numElements; i++) { sb.append(queue[i].toString()); if (i < numElements) sb.append("\n\t"); } return sb.toString(); } /** * A local class that holds the nodes of the priority tree */ private static class PriorityQueueNode { /** * the value to compare on, larger is better */ public double priority; /** * the associated data */ public Object data; public String toString() { return data + " ... [" + priority + "]"; } } }