View Javadoc

1   package cz.cuni.amis.utils.heap;
2   
3   import java.util.Collection;
4   import java.util.Comparator;
5   import java.util.HashMap;
6   import java.util.HashSet;
7   import java.util.Iterator;
8   import java.util.Set;
9   
10  /**
11   * Heap implementation as a {@link Collection} that provides "decreaseKey" operation. In order to do that, we're using
12   * a {@link HashMap} that holds references where the node lies within the heap, thus we're requiring that stored NODEs have {@link Object#equals(Object)} and
13   * {@link Object#hashCode()} implemented correctly.
14   * 
15   */
16  public class Heap<NODE> implements IHeap<NODE> {
17  	
18  	/**
19  	 * First element is always null, nodes are stored beginning with index [1].
20  	 */
21  	private NODE[] nodes;
22  	private int count;
23  	private int items;
24  	private HashMap<NODE, Integer> references;
25  	private Comparator<NODE> cmp;
26  	
27  	private void grow(){
28  		NODE[] tempNodes = (NODE[]) new Object[count*2];
29  		for (int i = 0; i <= items; ++i){
30  			tempNodes[i] = nodes[i];
31  		}
32  		nodes = tempNodes;
33  		count = count * 2;
34  	}
35  	
36  	private int left(int reference){
37  		return 2*reference;
38  	}
39  	
40  	private int right(int reference){
41  		return 2*reference+1;
42  	}
43  	
44  	private int upRef(int reference){
45  		return reference / 2;
46  	}
47  	
48  	private NODE getNode(int reference){
49  		while (reference >= count) 
50  			grow();		
51  		return nodes[reference];
52  	}
53  	
54  	private int downNode(int reference){
55  		NODE currentNode = getNode(reference);
56  		if (currentNode == null) {
57  			return reference;
58  		}
59  		NODE leftNode = null;
60  		NODE rightNode = null;
61  		int way = 0;
62  	
63  		while (true){
64  			way = 0;
65  			leftNode = getNode(left(reference));
66  			rightNode = getNode(right(reference));
67  		
68  			if ((leftNode == null) && (rightNode == null)){
69  				references.put(currentNode, reference);
70  				return reference;
71  			}
72  			if (rightNode == null) way = -1;
73  			else
74  				if (leftNode  == null) way = 1;
75  			if (way == 0) way = cmp.compare(leftNode, rightNode);
76  			
77  			if (way < 0){
78  				// we've got to ascend to the left
79  				if (cmp.compare(currentNode, leftNode) > 0){
80  					nodes[reference] = leftNode;
81  					references.put(leftNode, new Integer(reference));
82  					reference = left(reference);
83  					nodes[reference] = currentNode;					
84  				} else {
85  					references.put(currentNode, reference);				
86  					return reference;
87  				}				 
88  			} else {
89  				// we've got to ascend to the right
90  				if (cmp.compare(currentNode, rightNode) > 0){
91  					nodes[reference] = rightNode;
92  					references.put(rightNode, new Integer(reference));
93  					reference = right(reference);
94  					nodes[reference] = currentNode;					
95  					
96  				} else {
97  					references.put(currentNode, reference);				
98  					return reference;
99  				}				 
100 			}			
101 		}		
102 	}
103 	
104 	private int upNode(int reference){
105 		if (reference == 1) 
106 			return reference;
107 		NODE currentNode = getNode(reference);
108 		if (currentNode == null) 
109 			return reference;
110 		NODE upNode = null;
111 		while (reference > 1){
112 			upNode = getNode(upRef(reference));
113 			if (cmp.compare(currentNode, upNode) < 0){
114 				nodes[reference] = upNode;
115 				references.put(upNode, reference);				
116 				reference = upRef(reference);
117 			} else {
118 				break;
119 			}
120 		}
121 		nodes[reference] = currentNode;
122 		references.put(currentNode, reference);
123 		return reference;
124 	}
125 	
126 	private void initHeap(int capacity){
127 		if (capacity < 2) capacity = 2;
128 		nodes = (NODE[]) new Object[capacity];
129 		count = capacity;
130 		items = 0;
131 		references = new HashMap(capacity);
132 	}
133 	
134 	public Heap(Comparator<NODE> comp, int capacity){
135 		initHeap(capacity);	
136 		cmp = comp;
137 	}
138 	
139 	public Heap(Comparator<NODE> comp){
140 		initHeap(20);
141 		cmp = comp;
142 	}
143 	
144 	@Override
145 	public NODE getMin(){
146 		return nodes[1]; // capacity is always >= 2
147 	}
148 	
149 	@Override
150 	public boolean deleteMin(){
151 		if (items == 0) 
152 			return false;
153 		return remove(nodes[1], 1);
154 	}
155 	
156 	@Override
157 	public boolean decreaseKey(NODE arg0) {
158 		Integer reference = (Integer)references.get(arg0);
159 		if (reference == null){
160 			return add(arg0);
161 		}
162 		upNode(reference.intValue());
163 		return true;
164 	}
165 	
166 	@Override
167 	public boolean increaseKey(NODE arg0) {
168 		Integer reference = (Integer)references.get(arg0);
169 		if (reference == null){
170 			return add(arg0);
171 		}
172 		downNode(reference.intValue());
173 		return true;
174 	}
175 	
176 	@Override
177 	public boolean changedKey(NODE arg0) {
178 		Integer reference = (Integer)references.get(arg0);
179 		if (reference == null){
180 			return add(arg0);
181 		}
182 		upNode(reference.intValue());
183 		downNode(reference.intValue());
184 		return true;
185 	}
186 
187 	@Override
188 	public boolean add(NODE arg0) {
189 		Integer reference = (Integer)references.get(arg0);
190 		if (reference == null){
191 			getNode(items+1); // ensure that capacity is sufficient
192 			nodes[items+1] = arg0;
193 			upNode(items+1);
194 			items = items + 1;
195 			return true;
196 		} else {
197 			int tempRef = upNode(reference.intValue());
198 			if (tempRef == reference.intValue()) 
199 				downNode(reference.intValue());
200 			return true;
201 		}		
202 	}
203 
204 	@Override
205 	public boolean addAll(Collection arg0) {
206 		Iterator<NODE> iter = arg0.iterator();
207 		while (iter.hasNext())
208 			add(iter.next());		
209 		return true;
210 	}
211 	
212 	@Override
213 	public boolean addAll(NODE[] arg0) {
214 		boolean ok = true;
215 		for (int i = 0; i < arg0.length; ++i){
216 			ok = this.add(arg0[i]) && ok;
217 		}
218 		return ok;
219 	}
220 
221 	@Override
222 	public void clear() {
223 		for (int i = 0; i < count; ++i){
224 			nodes[i] = null;			
225 		}
226 		references.clear();
227 	}
228 
229 	@Override
230 	public boolean contains(Object arg0) {
231 		return references.containsKey(arg0);		
232 	}
233 
234 	@Override
235 	public boolean containsAll(Collection arg0) {
236 		for (Object node : arg0){
237 			if (!this.contains(node)) {
238 				return false;
239 			}
240 		}
241 		return true;
242 	}
243 	
244 	@Override
245 	public boolean containsAll(Object[] arg0) {
246 		for (int i = 0; i < arg0.length; ++i){
247 			if (!this.contains(arg0[i])) {
248 				return false;
249 			}
250 		}
251 		return true;
252 	}
253 
254 	@Override
255 	public boolean isEmpty() {
256 		return references.isEmpty();
257 	}
258 
259 	@Override
260 	public Iterator<NODE> iterator() {
261 		return new HeapIterator<NODE>(nodes, items, this);
262 	}
263 	
264 	private boolean remove(NODE arg0, int reference){
265 		references.remove(arg0);
266 		if (items == 1){
267 			nodes[1] = null;
268 			items = 0;
269 			return true;
270 		}
271 		nodes[reference] = nodes[items];
272 		nodes[items] = null;
273 		items = items - 1;
274 		downNode(reference);	
275 		return true;
276 	}
277 
278 	@Override
279 	public boolean remove(Object arg0) {
280 		Integer reference = (Integer)references.get(arg0);
281 		if (reference == null) 
282 			return false;
283 		return remove(reference.intValue());		
284 	}
285 	
286 	@Override
287 	public boolean removeAll(Collection arg0) {
288 		Iterator iter = arg0.iterator();
289 		while (iter.hasNext())
290 			remove(iter.next());
291 		return true;
292 	}
293 
294 	@Override
295 	public boolean retainAll(Collection arg0) {
296 		Iterator iter = references.keySet().iterator();
297 		Object item; Integer reference;
298 		while (iter.hasNext()){
299 			item = iter.next();
300 			reference = (Integer)references.get(item);
301 			if (!arg0.contains(item)) remove((NODE) item, reference.intValue());
302 		}
303 		return true;
304 	}
305 
306 	@Override
307 	public int size() {
308 		return items;
309 	}
310 	
311 	@Override
312 	public boolean empty() {
313 		return items == 0;
314 	}
315 
316 	@Override
317 	public Object[] toArray() {
318 		return references.keySet().toArray();
319 	}
320 
321 	@Override
322 	public Object[] toArray(Object[] arg0) {
323 		return references.keySet().toArray(arg0);
324 	}
325 	
326 	@Override
327 	public Set toSet(){
328 		return new HashSet(references.keySet());
329 	}
330 
331 	@Override
332 	public Comparator<NODE> getComparator() {
333 		return cmp;
334 	}
335 	
336 }