1 /*
2 * Copyright (c) 2003, The JUNG Authors
3 *
4 * All rights reserved.
5 *
6 * This software is open-source under the BSD license; see either
7 * "license.txt" or
8 * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
9 */
10 /*
11 *
12 * Created on Oct 29, 2003
13 */
14 package edu.uci.ics.jung.algorithms.util;
15
16 import java.util.AbstractCollection;
17 import java.util.Collection;
18 import java.util.Comparator;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.Map;
22 import java.util.NoSuchElementException;
23 import java.util.Queue;
24 import java.util.Vector;
25
26 import com.google.common.collect.Iterators;
27
28 /**
29 * An array-based binary heap implementation of a priority queue,
30 * which also provides
31 * efficient <code>update()</code> and <code>contains</code> operations.
32 * It contains extra infrastructure (a hash table) to keep track of the
33 * position of each element in the array; thus, if the key value of an element
34 * changes, it may be "resubmitted" to the heap via <code>update</code>
35 * so that the heap can reposition it efficiently, as necessary.
36 *
37 * @author Joshua O'Madadhain
38 */
39 public class MapBinaryHeap<T>
40 extends AbstractCollection<T>
41 implements Queue<T>
42 {
43 private Vector<T> heap = new Vector<T>(); // holds the heap as an implicit binary tree
44 private Map<T,Integer> object_indices = new HashMap<T,Integer>(); // maps each object in the heap to its index in the heap
45 private Comparator<T> comp;
46 private final static int TOP = 0; // the index of the top of the heap
47
48 /**
49 * Creates a <code>MapBinaryHeap</code> whose heap ordering
50 * is based on the ordering of the elements specified by <code>comp</code>.
51 * @param comp the comparator to use to order elements in the heap
52 */
53 public MapBinaryHeap(Comparator<T> comp)
54 {
55 initialize(comp);
56 }
57
58 /**
59 * Creates a <code>MapBinaryHeap</code> whose heap ordering
60 * will be based on the <i>natural ordering</i> of the elements,
61 * which must be <code>Comparable</code>.
62 */
63 public MapBinaryHeap()
64 {
65 initialize(new ComparableComparator());
66 }
67
68 /**
69 * Creates a <code>MapBinaryHeap</code> based on the specified
70 * collection whose heap ordering
71 * will be based on the <i>natural ordering</i> of the elements,
72 * which must be <code>Comparable</code>.
73 * @param c the collection of {@code Comparable} elements to add to the heap
74 */
75 public MapBinaryHeap(Collection<T> c)
76 {
77 this();
78 addAll(c);
79 }
80
81 /**
82 * Creates a <code>MapBinaryHeap</code> based on the specified collection
83 * whose heap ordering
84 * is based on the ordering of the elements specified by <code>c</code>.
85 * @param c the collection of elements to add to the heap
86 * @param comp the comparator to use for items in {@code c}
87 */
88 public MapBinaryHeap(Collection<T> c, Comparator<T> comp)
89 {
90 this(comp);
91 addAll(c);
92 }
93
94 private void initialize(Comparator<T> comp)
95 {
96 this.comp = comp;
97 clear();
98 }
99
100 /**
101 * @see Collection#clear()
102 */
103 @Override
104 public void clear()
105 {
106 object_indices.clear();
107 heap.clear();
108 }
109
110 /**
111 * Inserts <code>o</code> into this collection.
112 */
113 @Override
114 public boolean add(T o)
115 {
116 int i = heap.size(); // index 1 past the end of the heap
117 heap.setSize(i+1);
118 percolateUp(i, o);
119 return true;
120 }
121
122 /**
123 * Returns <code>true</code> if this collection contains no elements, and
124 * <code>false</code> otherwise.
125 */
126 @Override
127 public boolean isEmpty()
128 {
129 return heap.isEmpty();
130 }
131
132 /**
133 * Returns the element at the top of the heap; does not
134 * alter the heap.
135 */
136 public T peek()
137 {
138 if (heap.size() > 0)
139 return heap.elementAt(TOP);
140 else
141 return null;
142 }
143
144 /**
145 * @return the size of this heap
146 */
147 @Override
148 public int size()
149 {
150 return heap.size();
151 }
152
153 /**
154 * Informs the heap that this object's internal key value has been
155 * updated, and that its place in the heap may need to be shifted
156 * (up or down).
157 * @param o the object whose key value has been updated
158 */
159 public void update(T o)
160 {
161 // Since we don't know whether the key value increased or
162 // decreased, we just percolate up followed by percolating down;
163 // one of the two will have no effect.
164
165 int cur = object_indices.get(o).intValue(); // current index
166 int new_idx = percolateUp(cur, o);
167 percolateDown(new_idx);
168 }
169
170 @Override
171 public boolean contains(Object o)
172 {
173 return object_indices.containsKey(o);
174 }
175
176 /**
177 * Moves the element at position <code>cur</code> closer to
178 * the bottom of the heap, or returns if no further motion is
179 * necessary. Calls itself recursively if further motion is
180 * possible.
181 */
182 private void percolateDown(int cur)
183 {
184 int left = lChild(cur);
185 int right = rChild(cur);
186 int smallest;
187
188 if ((left < heap.size()) &&
189 (comp.compare(heap.elementAt(left), heap.elementAt(cur)) < 0)) {
190 smallest = left;
191 } else {
192 smallest = cur;
193 }
194
195 if ((right < heap.size()) &&
196 (comp.compare(heap.elementAt(right), heap.elementAt(smallest)) < 0)) {
197 smallest = right;
198 }
199
200 if (cur != smallest)
201 {
202 swap(cur, smallest);
203 percolateDown(smallest);
204 }
205 }
206
207 /**
208 * Moves the element <code>o</code> at position <code>cur</code>
209 * as high as it can go in the heap. Returns the new position of the
210 * element in the heap.
211 */
212 private int percolateUp(int cur, T o)
213 {
214 int i = cur;
215
216 while ((i > TOP) && (comp.compare(heap.elementAt(parent(i)), o) > 0))
217 {
218 T parentElt = heap.elementAt(parent(i));
219 heap.setElementAt(parentElt, i);
220 object_indices.put(parentElt, new Integer(i)); // reset index to i (new location)
221 i = parent(i);
222 }
223
224 // place object in heap at appropriate place
225 object_indices.put(o, new Integer(i));
226 heap.setElementAt(o, i);
227
228 return i;
229 }
230
231 /**
232 * Returns the index of the left child of the element at
233 * index <code>i</code> of the heap.
234 * @param i
235 * @return the index of the left child of the element at
236 * index <code>i</code> of the heap
237 */
238 private int lChild(int i)
239 {
240 return (i<<1) + 1;
241 }
242
243 /**
244 * Returns the index of the right child of the element at
245 * index <code>i</code> of the heap.
246 * @param i
247 * @return the index of the right child of the element at
248 * index <code>i</code> of the heap
249 */
250 private int rChild(int i)
251 {
252 return (i<<1) + 2;
253 }
254
255 /**
256 * Returns the index of the parent of the element at
257 * index <code>i</code> of the heap.
258 * @param i
259 * @return the index of the parent of the element at index i of the heap
260 */
261 private int parent(int i)
262 {
263 return (i-1)>>1;
264 }
265
266 /**
267 * Swaps the positions of the elements at indices <code>i</code>
268 * and <code>j</code> of the heap.
269 * @param i
270 * @param j
271 */
272 private void swap(int i, int j)
273 {
274 T iElt = heap.elementAt(i);
275 T jElt = heap.elementAt(j);
276
277 heap.setElementAt(jElt, i);
278 object_indices.put(jElt, new Integer(i));
279
280 heap.setElementAt(iElt, j);
281 object_indices.put(iElt, new Integer(j));
282 }
283
284 /**
285 * Comparator used if none is specified in the constructor.
286 * @author Joshua O'Madadhain
287 */
288 private class ComparableComparator implements Comparator<T>
289 {
290 /**
291 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
292 */
293 @SuppressWarnings("unchecked")
294 public int compare(T arg0, T arg1)
295 {
296 if (!(arg0 instanceof Comparable) || !(arg1 instanceof Comparable))
297 throw new IllegalArgumentException("Arguments must be Comparable");
298
299 return ((Comparable<T>)arg0).compareTo(arg1);
300 }
301 }
302
303 /**
304 * Returns an <code>Iterator</code> that does not support modification
305 * of the heap.
306 */
307 @Override
308 public Iterator<T> iterator()
309 {
310 return Iterators.<T>unmodifiableIterator(heap.iterator());
311 }
312
313 /**
314 * This data structure does not support the removal of arbitrary elements.
315 */
316 @Override
317 public boolean remove(Object o)
318 {
319 throw new UnsupportedOperationException();
320 }
321
322 /**
323 * This data structure does not support the removal of arbitrary elements.
324 */
325 @Override
326 public boolean removeAll(Collection<?> c)
327 {
328 throw new UnsupportedOperationException();
329 }
330
331 /**
332 * This data structure does not support the removal of arbitrary elements.
333 */
334 @Override
335 public boolean retainAll(Collection<?> c)
336 {
337 throw new UnsupportedOperationException();
338 }
339
340 public T element() throws NoSuchElementException
341 {
342 T top = this.peek();
343 if (top == null)
344 throw new NoSuchElementException();
345 return top;
346 }
347
348 public boolean offer(T o)
349 {
350 return add(o);
351 }
352
353 public T poll()
354 {
355 T top = this.peek();
356 if (top != null)
357 {
358 T bottom_elt = heap.lastElement();
359 heap.setElementAt(bottom_elt, TOP);
360 object_indices.put(bottom_elt, new Integer(TOP));
361
362 heap.setSize(heap.size() - 1); // remove the last element
363 if (heap.size() > 1)
364 percolateDown(TOP);
365
366 object_indices.remove(top);
367 }
368 return top;
369 }
370
371 public T remove()
372 {
373 T top = this.poll();
374 if (top == null)
375 throw new NoSuchElementException();
376 return top;
377 }
378
379 }