View Javadoc

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