1 pnkfelix 1.1.2.1  // BinHeapPriorityQueue.java, created Tue Jun  1 15:08:45 1999 by pnkfelix
  2 cananian 1.1.2.10 // Copyright (C) 1999 Felix S. Klock II <pnkfelix@mit.edu>
  3 pnkfelix 1.1.2.1  // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 pnkfelix 1.1.2.1  package harpoon.Util;
  5 pnkfelix 1.1.2.1  
  6 ovy      1.5      import java.util.Arrays;
  7 pnkfelix 1.1.2.1  import java.util.AbstractCollection;
  8 ovy      1.5      import java.util.HashMap;
  9 pnkfelix 1.1.2.1  import java.util.Iterator;
 10 ovy      1.5      import java.util.Map;
 11 ovy      1.5      import java.util.NoSuchElementException;
 12 pnkfelix 1.1.2.1  
 13 pnkfelix 1.1.2.1  /**
 14 pnkfelix 1.1.2.1   * <code>BinHeapPriorityQueue</code> is an implementation of the
 15 pnkfelix 1.1.2.1   * <code>PriorityQueue</code> interface. It supports O(1) time
 16 pnkfelix 1.1.2.1   * <code>peekMax</code> and O(lg n) time <code>insert</code> and 
 17 pnkfelix 1.1.2.1   * <code>removeMax</code> operations, assuming that
 18 cananian 1.1.2.7   * <code>ArrayList</code> is implemented in a reasonable manner.  The
 19 pnkfelix 1.1.2.1   * <code>remove</code> operation is probably slow however.
 20 pnkfelix 1.1.2.1   *
 21 pnkfelix 1.1.2.1   * Look into implementing a FibinocciHeap-based representation if
 22 pnkfelix 1.1.2.1   * speed becomes an issue. 
 23 pnkfelix 1.1.2.1   * 
 24 cananian 1.1.2.10  * @author  Felix S. Klock II <pnkfelix@mit.edu>
 25 ovy      1.6       * @version $Id: BinHeapPriorityQueue.java,v 1.6 2002/04/25 00:39:51 ovy Exp $
 26 pnkfelix 1.1.2.1   */
 27 pnkfelix 1.1.2.1  public class BinHeapPriorityQueue extends AbstractCollection implements MaxPriorityQueue {
 28 ovy      1.5          private HashMap item2entry;
 29 ovy      1.5          private Entry[] heap;
 30 ovy      1.5          private int size;
 31 pnkfelix 1.1.2.1  
 32 ovy      1.5          private final static int DEFAULT_SIZE=16;
 33 pnkfelix 1.1.2.1      
 34 pnkfelix 1.1.2.1      public BinHeapPriorityQueue() {
 35 ovy      1.5              this(DEFAULT_SIZE);
 36 ovy      1.5          }
 37 ovy      1.5      
 38 ovy      1.5          public BinHeapPriorityQueue(int size) {
 39 ovy      1.5              item2entry = new HashMap(size);
 40 ovy      1.5              heap = new Entry[size];
 41 ovy      1.5              size = 0;
 42 ovy      1.5          }
 43 ovy      1.5      
 44 ovy      1.5      
 45 ovy      1.5          public boolean insert(Object item, int priority) {
 46 ovy      1.5      
 47 ovy      1.5              // already exists? then simply set priority
 48 ovy      1.5              if (item2entry.containsKey(item)) {
 49 ovy      1.5                  return setPriority(item, priority) != priority;
 50 ovy      1.5              }
 51 ovy      1.5      
 52 ovy      1.5              ensureCapacity(size+1);
 53 ovy      1.5              
 54 ovy      1.5              Entry entry = new Entry();
 55 ovy      1.5              entry.item = item;
 56 ovy      1.5              entry.priority = priority;
 57 ovy      1.5      
 58 ovy      1.5              // insert at last position in heap
 59 ovy      1.5              entry.heapIndex = size;
 60 ovy      1.5              heap[size] = entry;
 61 ovy      1.5              size++;
 62 ovy      1.5              
 63 ovy      1.5              // now percolate to go up the hierarchy
 64 ovy      1.5              percolate(entry);
 65 ovy      1.5      
 66 ovy      1.5              // the collection has changed
 67 ovy      1.5              return true;
 68 ovy      1.5          }
 69 ovy      1.5      
 70 ovy      1.5          public int getPriority(Object item) {
 71 ovy      1.5              Entry entry = (Entry) item2entry.get(item);
 72 ovy      1.5      
 73 ovy      1.5              if (entry == null) {
 74 ovy      1.5                  throw new NoSuchElementException(item.toString());
 75 ovy      1.5              }
 76 ovy      1.5      
 77 ovy      1.5              return entry.priority;
 78 pnkfelix 1.1.2.1      }
 79 pnkfelix 1.1.2.1      
 80 ovy      1.5      
 81 ovy      1.5          public int setPriority(Object item, int priority) {
 82 ovy      1.5              Entry entry = (Entry) item2entry.get(item);
 83 ovy      1.5      
 84 ovy      1.5              if (entry == null) {
 85 ovy      1.5                  throw new NoSuchElementException(item.toString());
 86 ovy      1.5              }
 87 ovy      1.5      
 88 ovy      1.5              int oldPriority = entry.priority;
 89 ovy      1.5              entry.priority = priority;
 90 ovy      1.5              
 91 ovy      1.5              priorityChanged(entry, priority - oldPriority);
 92 ovy      1.5      
 93 ovy      1.5              return oldPriority;
 94 ovy      1.5          }
 95 ovy      1.5      
 96 ovy      1.5          public void changePriority(Object item, int delta) {
 97 ovy      1.5              Entry entry = (Entry) item2entry.get(item);
 98 ovy      1.5      
 99 ovy      1.5              if (entry == null) {
100 ovy      1.5                  throw new NoSuchElementException(item.toString());
101 ovy      1.5              }
102 ovy      1.5      
103 ovy      1.5              entry.priority += delta;
104 ovy      1.5              priorityChanged(entry, delta);
105 pnkfelix 1.1.2.1      }
106 pnkfelix 1.1.2.1  
107 pnkfelix 1.1.2.1      public Object peekMax() {
108 ovy      1.5              return heap[0].item;
109 pnkfelix 1.1.2.1      }
110 ovy      1.5          
111 ovy      1.5          public Object deleteMax() {
112 ovy      1.5              if (size == 0) {
113 ovy      1.5                  throw new NoSuchElementException("Heap is empty");
114 ovy      1.5              }
115 ovy      1.5              
116 ovy      1.5              Object item = heap[0].item;
117 pnkfelix 1.1.2.1  
118 ovy      1.5              removeEntry(heap[0]);
119 ovy      1.5      
120 ovy      1.5              return item;
121 ovy      1.5          }
122 ovy      1.5          
123 ovy      1.5          
124 ovy      1.5          public boolean remove(Object item) {
125 ovy      1.5              Entry entry = (Entry) item2entry.get(item);
126 ovy      1.5      
127 ovy      1.5              if (entry == null) return false;
128 ovy      1.5      
129 ovy      1.5              removeEntry(entry);
130 ovy      1.5      
131 ovy      1.5              return true;
132 ovy      1.5          }
133 ovy      1.5      
134 ovy      1.5          public boolean contains(Object item) {
135 ovy      1.5              return item2entry.containsKey(item);
136 ovy      1.5          }
137 pnkfelix 1.1.2.2  
138 ovy      1.5          public Iterator iterator() {
139 ovy      1.5              return new HeapIterator();
140 pnkfelix 1.1.2.1      }
141 pnkfelix 1.1.2.1  
142 pnkfelix 1.1.2.1      public void clear() {
143 ovy      1.5              item2entry.clear();
144 ovy      1.5              Arrays.fill(heap, null);
145 ovy      1.5              size = 0;
146 pnkfelix 1.1.2.1      }
147 ovy      1.5      
148 ovy      1.5          public int size() {
149 ovy      1.5              return size;
150 pnkfelix 1.1.2.1      }
151 pnkfelix 1.1.2.1  
152 ovy      1.6          public String toString() {
153 ovy      1.6              StringBuffer sb = new StringBuffer("[");
154 ovy      1.6              
155 ovy      1.6              for (int i = 0; i<size; i++) {
156 ovy      1.6                  sb.append(" (").append(heap[i].item).append(", ")
157 ovy      1.6                      .append(heap[i].priority).append(")");
158 ovy      1.6              }
159 ovy      1.6      
160 ovy      1.6              return sb.append(" ]").toString();
161 ovy      1.6          }
162 ovy      1.6      
163 ovy      1.5          private void removeEntry(Entry entry) {
164 ovy      1.5              Entry last = heap[size - 1];
165 ovy      1.5              
166 ovy      1.5              swap(entry, last);
167 ovy      1.6      
168 ovy      1.5              heap[size - 1] = null;
169 ovy      1.5              size--;
170 ovy      1.5      
171 ovy      1.6              priorityChanged(last, last.priority - entry.priority);
172 ovy      1.6              
173 ovy      1.5              item2entry.remove(entry.item);
174 pnkfelix 1.1.2.1      }
175 pnkfelix 1.1.2.1  
176 ovy      1.5          private void ensureCapacity(int size) {
177 ovy      1.5              if (heap.length >= size) return;
178 ovy      1.5      
179 ovy      1.5              Entry[] newHeap = new Entry[ Math.max(size, heap.length*2) ];
180 ovy      1.5              
181 ovy      1.5              System.arraycopy(heap, 0, newHeap, 0, heap.length);
182 ovy      1.5      
183 ovy      1.5              heap = newHeap;
184 pnkfelix 1.1.2.1      }
185 ovy      1.5              
186 ovy      1.5          private void priorityChanged(Entry entry, int delta) {
187 ovy      1.5              if (delta > 0) {
188 ovy      1.5                  // priority has grown, move up
189 ovy      1.5                  percolate(entry);
190 ovy      1.5              } else if (delta < 0) {
191 ovy      1.5                  // priority has decreased, move down
192 ovy      1.5                  siftDown(entry);
193 ovy      1.5              }
194 ovy      1.5          }
195 ovy      1.5      
196 ovy      1.5          private void percolate(Entry entry) {
197 ovy      1.5              while (entry.heapIndex > 0) {
198 ovy      1.5                  Entry parent = heap[ (entry.heapIndex-1) / 2 ];
199 pnkfelix 1.1.2.1  
200 ovy      1.5                  // are we better than parent? if not, we're in the right place
201 ovy      1.5                  if (entry.priority <=  parent.priority) {
202 ovy      1.5                      break;
203 ovy      1.5                  }
204 ovy      1.5      
205 ovy      1.5                  swap(parent, entry);
206 ovy      1.5              }
207 pnkfelix 1.1.2.1      }
208 pnkfelix 1.1.2.1  
209 ovy      1.5          private void siftDown(Entry entry) {
210 ovy      1.5              while (entry.heapIndex*2 + 1 < size) {
211 ovy      1.5                  Entry leftSon = heap[entry.heapIndex*2 + 1];
212 ovy      1.5                  Entry rightSon = entry.heapIndex*2 + 2 < size ?
213 ovy      1.5                      heap[entry.heapIndex*2 + 2] : null;
214 ovy      1.5      
215 ovy      1.5                  Entry maxSon =
216 ovy      1.5                      (rightSon == null || leftSon.priority > rightSon.priority) ?
217 ovy      1.5                      leftSon : rightSon;
218 ovy      1.5      
219 ovy      1.5                  // are we better than our best son? if so, we're in the right place
220 ovy      1.5                  if (entry.priority >= maxSon.priority) {
221 ovy      1.5                      break;
222 ovy      1.5                  }
223 ovy      1.5      
224 ovy      1.5                  swap(entry, maxSon);
225 ovy      1.5              }
226 pnkfelix 1.1.2.1      }
227 pnkfelix 1.1.2.1  
228 ovy      1.5          
229 ovy      1.5          private void swap(Entry e1, Entry e2) {
230 ovy      1.5              int e1_index = e1.heapIndex;
231 ovy      1.5              int e2_index = e2.heapIndex;
232 ovy      1.5                          
233 ovy      1.5              e1.heapIndex = e2_index;
234 ovy      1.5              heap[e2_index] = e1;
235 ovy      1.5      
236 ovy      1.5              e2.heapIndex = e1_index;
237 ovy      1.5              heap[e1_index] = e2;
238 pnkfelix 1.1.2.1      }
239 pnkfelix 1.1.2.1  
240 ovy      1.5          
241 pnkfelix 1.1.2.1  
242 ovy      1.5          class Entry {
243 ovy      1.5              int priority;
244 ovy      1.5              int heapIndex;
245 ovy      1.5              Object item;
246 ovy      1.5          }
247 ovy      1.5      
248 ovy      1.5          // wrapper around the hashMap's entry iterator
249 ovy      1.5          class HeapIterator implements Iterator {
250 ovy      1.5              Iterator hashIterator;
251 ovy      1.5              Entry current;
252 ovy      1.5              
253 ovy      1.5              HeapIterator() {
254 ovy      1.5                  hashIterator = item2entry.entrySet().iterator();
255 ovy      1.5              }
256 ovy      1.5      
257 ovy      1.5              public boolean hasNext() {
258 ovy      1.5                  return hashIterator.hasNext();
259 ovy      1.5              }
260 ovy      1.5      
261 ovy      1.5              public Object next() {
262 ovy      1.5                  Map.Entry hashEntry = ((Map.Entry) hashIterator.next());
263 ovy      1.5                  current = (Entry) hashEntry.getValue();
264 ovy      1.5                  return hashEntry.getKey();
265 ovy      1.5              }
266 ovy      1.5      
267 ovy      1.5              public void remove() {
268 ovy      1.5                  hashIterator.remove();
269 ovy      1.5                  removeEntry(current);
270 ovy      1.5              }
271 pnkfelix 1.1.2.1      }
272 cananian 1.2      }