View Javadoc

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