001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.jikesrvm.util;
014
015 import org.jikesrvm.VM;
016
017 /**
018 * This class implements a priority queue using the standard
019 * (balanced partially-ordered tree, i.e., "heap") algorithm.
020 * Smaller priority objects are in the front of the queue.
021 */
022 public class PriorityQueueRVM {
023
024 /**
025 * the queue, we use elements 1..queue.length
026 */
027 private PriorityQueueNode[] queue;
028
029 /**
030 * the number of elements actually in the queue
031 */
032 private int numElements = 0;
033
034 protected PriorityQueueRVM() {
035 queue = new PriorityQueueNode[20];
036
037 // We don't use element #0
038 for (int i = 1; i < queue.length; i++) {
039 queue[i] = new PriorityQueueNode();
040 }
041 }
042
043 /**
044 * Determines number of elements in the queue
045 * @return number of elements in the queue
046 */
047 public final synchronized int numElements() {
048 return numElements;
049 }
050
051 /**
052 * Checks if the queue is empty
053 * @return is the queue empty?
054 */
055 protected final synchronized boolean isEmpty() {
056 return numElements == 0;
057 }
058
059 /**
060 * Starting at the position passed, swap with parent until heap condition
061 * is satisfied, i.e., bubble up
062 * @param startingElement the position to start at
063 */
064 private void reheapify(int startingElement) {
065 int current = startingElement;
066 int parent = numElements / 2;
067 // keep checking parents that violate the magic condition
068 while (parent > 0 && queue[parent].priority < queue[current].priority) {
069 // System.out.println("Parent: "+ parent +", Current: "+ current);
070 // System.out.println("Contents before: "+ this);
071 // exchange parrent and current values
072 PriorityQueueNode tmp = queue[parent];
073 queue[parent] = queue[current];
074 queue[current] = tmp;
075
076 // System.out.println("Contents after: "+ this);
077 // go up 1 level
078 current = parent;
079 parent = parent / 2;
080 }
081 }
082
083 /**
084 * Insert the object passed with the priority value passed
085 * @param _priority the priority of the inserted object
086 * @param _data the object to insert
087 */
088 public synchronized void insert(double _priority, Object _data) {
089 numElements++;
090
091 if (numElements == queue.length) {
092 PriorityQueueNode[] tmp = new PriorityQueueNode[(int) (queue.length * 1.5)];
093 System.arraycopy(queue, 0, tmp, 0, queue.length);
094 for (int i = queue.length; i < tmp.length; i++) {
095 tmp[i] = new PriorityQueueNode();
096 }
097 queue = tmp;
098 }
099
100 queue[numElements].data = _data;
101 queue[numElements].priority = _priority;
102
103 // re-heapify
104 reheapify(numElements);
105 }
106
107 /**
108 * Remove and return the front (minimum) object
109 * @return the front (minimum) object or null if the queue is empty.
110 */
111 public synchronized Object deleteMin() {
112 if (isEmpty()) return null;
113
114 Object returnValue = queue[1].data;
115 // move the "last" element to the root and reheapify by pushing it down
116 queue[1].priority = queue[numElements].priority;
117 queue[1].data = queue[numElements].data;
118 numElements--;
119
120 // reheapify!!!
121 int current = 1;
122
123 // The children live at 2*current and 2*current+1
124 int child1 = 2 * current;
125 while (child1 <= numElements) {
126 int child2 = 2 * current + 1;
127
128 // find the smaller of the two children
129 int smaller;
130 if (child2 <= numElements && queue[child2].priority > queue[child1].priority) {
131 smaller = child2;
132 } else {
133 smaller = child1;
134 }
135
136 if (queue[smaller].priority <= queue[current].priority) {
137 break;
138 } else {
139 // exchange parrent and current values
140 PriorityQueueNode tmp = queue[smaller];
141 queue[smaller] = queue[current];
142 queue[current] = tmp;
143
144 // go down 1 level
145 current = smaller;
146 child1 = 2 * current;
147 }
148 }
149 return returnValue;
150 }
151
152 /**
153 * Return the priority of front object without removing it
154 * @return the priority of the front object
155 */
156 public final synchronized double rootValue() {
157 if (VM.VerifyAssertions) VM._assert(!isEmpty());
158
159 return queue[1].priority;
160 }
161
162 /**
163 * Prints the contents of the queue
164 * @return the queue contents
165 */
166 public synchronized String toString() {
167 final StringBuilder sb = new StringBuilder(" --> ");
168 sb.append("Dumping Queue with ");
169 sb.append(numElements);
170 sb.append(" elements:\n");
171 if (numElements >= 1) sb.append("\t");
172
173 for (int i = 1; i <= numElements; i++) {
174 sb.append(queue[i].toString());
175 if (i < numElements) sb.append("\n\t");
176 }
177 return sb.toString();
178 }
179
180 /**
181 * A local class that holds the nodes of the priority tree
182 */
183 private static class PriorityQueueNode {
184
185 /**
186 * the value to compare on, larger is better
187 */
188 public double priority;
189
190 /**
191 * the associated data
192 */
193 public Object data;
194
195 public String toString() {
196 return data + " ... [" + priority + "]";
197 }
198 }
199 }
200