13 namespace hugo { |
13 namespace hugo { |
14 |
14 |
15 /// An implementation of the Fibonacci Heap. |
15 /// An implementation of the Fibonacci Heap. |
16 |
16 |
17 /** |
17 /** |
18 This class implements the \e Fibonacci \e heap data structure. A \e |
18 This class implements the \e Fibonacci \e heap data structure. A \e heap |
19 heap is a data structure for storing items with specified priorities, |
19 is a data structure for storing items with specified values called \e |
20 such that finding the item with minimum priority is efficient. In a |
20 priorities, such that finding the item with minimum priority with respect |
21 heap one can change the priority of an item, and to add or erase an |
21 to \e Compare is efficient. In a heap one can change the priority of an |
22 item. |
22 item, add or erase an item, etc. |
23 |
23 |
24 The methods \ref increase and \ref erase are not efficient, in |
24 The methods \ref increase and \ref erase are not efficient in a Fibonacci |
25 case of many calls to these operations, it is better to use |
25 heap. In case of many calls to these operations, it is better to use a |
26 a binary heap. |
26 \e binary \e heap. |
27 |
27 |
28 /param Item The type of the items to be stored. |
28 \param Item The type of the items to be stored. |
29 /param Prio The type of the priority of the items. |
29 \param Prio The type of the priority of the items. |
30 /param ItemIntMap A read and writable Item int map, for the usage of |
30 \param ItemIntMap A read and writable Item int map, for the usage of |
31 the heap. |
31 the heap. |
32 /param Compare A class for the comparison of the priorities. The |
32 \param Compare A class for the comparison of the priorities. The |
33 default is \c std::less<Prio>. |
33 default is \c std::less<Prio>. |
34 |
34 |
35 */ |
35 */ |
36 |
36 |
37 #ifdef DOXYGEN |
37 #ifdef DOXYGEN |
65 IN_HEAP = 0, |
65 IN_HEAP = 0, |
66 PRE_HEAP = -1, |
66 PRE_HEAP = -1, |
67 POST_HEAP = -2 |
67 POST_HEAP = -2 |
68 }; |
68 }; |
69 |
69 |
70 public : |
|
71 |
|
72 FibHeap(ItemIntMap &_iimap) : minimum(0), iimap(_iimap), num_items() {} |
70 FibHeap(ItemIntMap &_iimap) : minimum(0), iimap(_iimap), num_items() {} |
73 FibHeap(ItemIntMap &_iimap, const Compare &_comp) : minimum(0), |
71 FibHeap(ItemIntMap &_iimap, const Compare &_comp) : minimum(0), |
74 iimap(_iimap), comp(_comp), num_items() {} |
72 iimap(_iimap), comp(_comp), num_items() {} |
75 |
73 |
76 ///The number of items stored in the heap. |
74 ///The number of items stored in the heap. |
77 |
75 |
78 /** |
76 /** |
79 Returns the number of items stored in the heap. |
77 Returns the number of items stored in the heap. |
80 */ |
78 */ |
81 int size() const { return num_items; } |
79 int size() const { return num_items; } |
82 |
80 |
83 ///Checks if the heap stores no items. |
81 ///Checks if the heap stores no items. |
84 |
82 |
85 /** |
83 /** |
86 Returns true iff the heap stores no items. |
84 Returns \c true iff the heap stores no items. |
87 */ |
85 */ |
88 bool empty() const { return num_items==0; } |
86 bool empty() const { return num_items==0; } |
89 |
87 |
90 ///Item \c item gets to the heap with priority \c value independently if \c item was already there. |
88 ///\c item gets to the heap with priority \c value independently if \c item was already there. |
91 |
89 |
92 /** |
90 /** |
93 This method calls \ref push(item, value) if \c item is not |
91 This method calls \ref push(\c item, \c value) if \c item is not |
94 stored in the heap, and it calls \ref decrease(it, \c value) or |
92 stored in the heap and it calls \ref decrease(\c item, \c value) or |
95 \ref increase(it, \c value) otherwise. |
93 \ref increase(\c item, \c value) otherwise. |
96 */ |
94 */ |
97 void set (Item const item, PrioType const value); //vigyazat: az implementacioban it van |
95 void set (Item const item, PrioType const value); |
98 |
96 |
99 ///Adds \c item to the heap with priority \c value. |
97 ///Adds \c item to the heap with priority \c value. |
100 |
98 |
101 /** |
99 /** |
102 Adds \c item to the heap with priority \c value. |
100 Adds \c item to the heap with priority \c value. |
103 \pre \c item must not be stored in the heap. |
101 \pre \c item must not be stored in the heap. |
104 */ |
102 */ |
105 void push (Item const it, PrioType const value); /*vigyazat: az implementacioban it van*/ |
103 void push (Item const item, PrioType const value); |
106 |
104 |
107 |
105 |
108 ///Returns the item having the minimum priority w.r.t. Compare. |
106 ///Returns the item having the minimum priority w.r.t. Compare. |
109 |
107 |
110 /** |
108 /** |
155 |
155 |
156 /** |
156 /** |
157 This method deletes \c item from the heap, if \c item was already |
157 This method deletes \c item from the heap, if \c item was already |
158 stored in the heap. It is quite inefficient in Fibonacci heaps. |
158 stored in the heap. It is quite inefficient in Fibonacci heaps. |
159 */ |
159 */ |
160 void erase (const Item& item); /*vigyazat: az implementacioban it van*/ |
160 void erase (const Item& item); |
161 |
161 |
162 ///Decreases the priority of \c item to \c value. |
162 ///Decreases the priority of \c item to \c value. |
163 |
163 |
164 /** |
164 /** |
165 This method decreases the priority of \c item to \c value. |
165 This method decreases the priority of \c item to \c value. |
166 \pre \c item must be stored in the heap with priority at least \c |
166 \pre \c item must be stored in the heap with priority at least \c |
167 value w.r.t. Compare. |
167 value w.r.t. Compare. |
168 */ |
168 */ |
169 void decrease (Item item, PrioType const value); /*vigyazat: az implementacioban it van*/ |
169 void decrease (Item item, PrioType const value); |
170 |
170 |
171 |
171 |
172 ///Increases the priority of \c item to \c value. |
172 ///Increases the priority of \c item to \c value. |
173 |
173 |
174 /** |
174 /** |
175 This method sets the priority of \c item to \c value. Though |
175 This method sets the priority of \c item to \c value. Though |
176 there is no precondition on the priority of \c item, this |
176 there is no precondition on the priority of \c item, this |
177 method should be used only if one wants to \e increase |
177 method should be used only if there is a need to really \e increase |
178 (w.r.t. Compare) the priority of \c item, because this |
178 (w.r.t. Compare) the priority of \c item, because this |
179 method is inefficient. |
179 method is inefficient. |
180 */ |
180 */ |
181 void increase (Item it, PrioType const value) { |
181 void increase (Item item, PrioType const value) { |
182 erase(it); |
182 erase(item); |
183 push(it, value); |
183 push(item, value); |
184 } |
184 } |
185 |
185 |
186 |
186 |
187 ///Tells if \c item is in, was in, or has not been in the heap. |
187 ///Tells if \c item is in, was already in, or has never been in the heap. |
188 |
188 |
189 /** |
189 /** |
190 This method returns PRE_HEAP if \c item has never been in the |
190 This method returns PRE_HEAP if \c item has never been in the |
191 heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP |
191 heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP |
192 otherwise. In the latter case it is possible that \c item will |
192 otherwise. In the latter case it is possible that \c item will |
193 get back to the heap again. |
193 get back to the heap again. |
194 */ |
194 */ |
195 state_enum state(const Item &it); /*vigyazat: az implementacioban it van*/ |
195 state_enum state(const Item &item) const { |
196 |
196 int i=iimap[item]; |
|
197 if( i>=0 ) { |
|
198 if ( container[i].in ) i=0; |
|
199 else i=-2; |
|
200 } |
|
201 return state_enum(i); |
|
202 } |
|
203 |
|
204 private: |
|
205 |
|
206 void balance(); |
|
207 void makeroot(int c); |
|
208 void cut(int a, int b); |
|
209 void cascade(int a); |
|
210 void fuse(int a, int b); |
|
211 void unlace(int a); |
|
212 |
|
213 |
|
214 class store { |
|
215 friend class FibHeap; |
|
216 |
|
217 Item name; |
|
218 int parent; |
|
219 int left_neighbor; |
|
220 int right_neighbor; |
|
221 int child; |
|
222 int degree; |
|
223 bool marked; |
|
224 bool in; |
|
225 PrioType prio; |
|
226 |
|
227 store() : parent(-1), child(-1), degree(), marked(false), in(true) {} |
|
228 }; |
|
229 }; |
|
230 |
197 |
231 |
198 |
232 |
199 // ********************************************************************** |
233 // ********************************************************************** |
200 // IMPLEMENTATIONS |
234 // IMPLEMENTATIONS |
201 // ********************************************************************** |
235 // ********************************************************************** |
202 |
236 |
203 |
237 template <typename Item, typename Prio, typename ItemIntMap, |
204 void set (Item const it, PrioType const value) { |
238 typename Compare> |
205 int i=iimap[it]; |
239 void FibHeap<Item, Prio, ItemIntMap, Compare>::set |
206 if ( i >= 0 && container[i].in ) { |
240 (Item const item, PrioType const value) |
207 if ( comp(value, container[i].prio) ) decrease(it, value); |
241 { |
208 if ( comp(container[i].prio, value) ) increase(it, value); |
242 int i=iimap[item]; |
209 } else push(it, value); |
243 if ( i >= 0 && container[i].in ) { |
210 } |
244 if ( comp(value, container[i].prio) ) decrease(item, value); |
211 |
245 if ( comp(container[i].prio, value) ) increase(item, value); |
212 |
246 } else push(item, value); |
213 void push (Item const it, PrioType const value) { |
247 } |
214 int i=iimap[it]; |
248 |
|
249 template <typename Item, typename Prio, typename ItemIntMap, |
|
250 typename Compare> |
|
251 void FibHeap<Item, Prio, ItemIntMap, Compare>::push |
|
252 (Item const item, PrioType const value) { |
|
253 int i=iimap[item]; |
215 if ( i < 0 ) { |
254 if ( i < 0 ) { |
216 int s=container.size(); |
255 int s=container.size(); |
217 iimap.set( it, s ); |
256 iimap.set( item, s ); |
218 store st; |
257 store st; |
219 st.name=it; |
258 st.name=item; |
220 container.push_back(st); |
259 container.push_back(st); |
221 i=s; |
260 i=s; |
222 } else { |
261 } else { |
223 container[i].parent=container[i].child=-1; |
262 container[i].parent=container[i].child=-1; |
224 container[i].degree=0; |
263 container[i].degree=0; |
270 balance(); |
310 balance(); |
271 } // the case where there are more roots |
311 } // the case where there are more roots |
272 --num_items; |
312 --num_items; |
273 } |
313 } |
274 |
314 |
275 |
315 |
276 void erase (const Item& it) { |
316 template <typename Item, typename Prio, typename ItemIntMap, |
277 int i=iimap[it]; |
317 typename Compare> |
|
318 void FibHeap<Item, Prio, ItemIntMap, Compare>::erase |
|
319 (const Item& item) { |
|
320 int i=iimap[item]; |
278 |
321 |
279 if ( i >= 0 && container[i].in ) { |
322 if ( i >= 0 && container[i].in ) { |
280 if ( container[i].parent!=-1 ) { |
323 if ( container[i].parent!=-1 ) { |
281 int p=container[i].parent; |
324 int p=container[i].parent; |
282 cut(i,p); |
325 cut(i,p); |
283 cascade(p); |
326 cascade(p); |
284 } |
327 } |
285 minimum=i; //As if its prio would be -infinity |
328 minimum=i; //As if its prio would be -infinity |
286 pop(); |
329 pop(); |
287 } |
330 } |
288 } |
331 } |
289 |
332 |
290 |
333 template <typename Item, typename Prio, typename ItemIntMap, |
291 void decrease (Item it, PrioType const value) { |
334 typename Compare> |
292 int i=iimap[it]; |
335 void FibHeap<Item, Prio, ItemIntMap, Compare>::decrease |
|
336 (Item item, PrioType const value) { |
|
337 int i=iimap[item]; |
293 container[i].prio=value; |
338 container[i].prio=value; |
294 int p=container[i].parent; |
339 int p=container[i].parent; |
295 |
340 |
296 if ( p!=-1 && comp(value, container[p].prio) ) { |
341 if ( p!=-1 && comp(value, container[p].prio) ) { |
297 cut(i,p); |
342 cut(i,p); |
298 cascade(p); |
343 cascade(p); |
299 } |
344 } |
300 if ( comp(value, container[minimum].prio) ) minimum=i; |
345 if ( comp(value, container[minimum].prio) ) minimum=i; |
301 } |
346 } |
302 |
347 |
303 |
348 |
304 state_enum state(const Item &it) const { |
349 template <typename Item, typename Prio, typename ItemIntMap, |
305 int i=iimap[it]; |
350 typename Compare> |
306 if( i>=0 ) { |
351 void FibHeap<Item, Prio, ItemIntMap, Compare>::balance() { |
307 if ( container[i].in ) i=0; |
|
308 else i=-2; |
|
309 } |
|
310 return state_enum(i); |
|
311 } |
|
312 |
|
313 |
|
314 private: |
|
315 |
|
316 void balance() { |
|
317 |
352 |
318 int maxdeg=int( floor( 2.08*log(double(container.size()))))+1; |
353 int maxdeg=int( floor( 2.08*log(double(container.size()))))+1; |
319 |
354 |
320 std::vector<int> A(maxdeg,-1); |
355 std::vector<int> A(maxdeg,-1); |
321 |
356 |
354 if ( comp(container[s].prio, container[minimum].prio) ) minimum=s; |
389 if ( comp(container[s].prio, container[minimum].prio) ) minimum=s; |
355 s=container[s].right_neighbor; |
390 s=container[s].right_neighbor; |
356 } while ( s != m ); |
391 } while ( s != m ); |
357 } |
392 } |
358 |
393 |
359 |
394 template <typename Item, typename Prio, typename ItemIntMap, |
360 void makeroot (int c) { |
395 typename Compare> |
|
396 void FibHeap<Item, Prio, ItemIntMap, Compare>::makeroot |
|
397 (int c) { |
361 int s=c; |
398 int s=c; |
362 do { |
399 do { |
363 container[s].parent=-1; |
400 container[s].parent=-1; |
364 s=container[s].right_neighbor; |
401 s=container[s].right_neighbor; |
365 } while ( s != c ); |
402 } while ( s != c ); |
366 } |
403 } |
367 |
404 |
368 |
405 |
369 void cut (int a, int b) { |
406 template <typename Item, typename Prio, typename ItemIntMap, |
370 /* |
407 typename Compare> |
371 *Replacing a from the children of b. |
408 void FibHeap<Item, Prio, ItemIntMap, Compare>::cut |
372 */ |
409 (int a, int b) { |
373 --container[b].degree; |
410 /* |
374 |
411 *Replacing a from the children of b. |
375 if ( container[b].degree !=0 ) { |
412 */ |
376 int child=container[b].child; |
413 --container[b].degree; |
377 if ( child==a ) |
414 |
378 container[b].child=container[child].right_neighbor; |
415 if ( container[b].degree !=0 ) { |
379 unlace(a); |
416 int child=container[b].child; |
380 } |
417 if ( child==a ) |
381 |
418 container[b].child=container[child].right_neighbor; |
382 |
419 unlace(a); |
383 /*Lacing a to the roots.*/ |
420 } |
384 int right=container[minimum].right_neighbor; |
421 |
385 container[minimum].right_neighbor=a; |
422 |
386 container[a].left_neighbor=minimum; |
423 /*Lacing a to the roots.*/ |
387 container[a].right_neighbor=right; |
424 int right=container[minimum].right_neighbor; |
388 container[right].left_neighbor=a; |
425 container[minimum].right_neighbor=a; |
389 |
426 container[a].left_neighbor=minimum; |
390 container[a].parent=-1; |
427 container[a].right_neighbor=right; |
391 container[a].marked=false; |
428 container[right].left_neighbor=a; |
392 } |
429 |
393 |
430 container[a].parent=-1; |
394 |
431 container[a].marked=false; |
395 void cascade (int a) |
432 } |
|
433 |
|
434 |
|
435 template <typename Item, typename Prio, typename ItemIntMap, |
|
436 typename Compare> |
|
437 void FibHeap<Item, Prio, ItemIntMap, Compare>::cascade |
|
438 (int a) |
396 { |
439 { |
397 if ( container[a].parent!=-1 ) { |
440 if ( container[a].parent!=-1 ) { |
398 int p=container[a].parent; |
441 int p=container[a].parent; |
399 |
442 |
400 if ( container[a].marked==false ) container[a].marked=true; |
443 if ( container[a].marked==false ) container[a].marked=true; |
428 ++container[a].degree; |
474 ++container[a].degree; |
429 |
475 |
430 container[b].marked=false; |
476 container[b].marked=false; |
431 } |
477 } |
432 |
478 |
433 |
479 |
434 /* |
480 /* |
435 *It is invoked only if a has siblings. |
481 *It is invoked only if a has siblings. |
436 */ |
482 */ |
437 void unlace (int a) { |
483 template <typename Item, typename Prio, typename ItemIntMap, |
|
484 typename Compare> |
|
485 void FibHeap<Item, Prio, ItemIntMap, Compare>::unlace |
|
486 (int a) { |
438 int leftn=container[a].left_neighbor; |
487 int leftn=container[a].left_neighbor; |
439 int rightn=container[a].right_neighbor; |
488 int rightn=container[a].right_neighbor; |
440 container[leftn].right_neighbor=rightn; |
489 container[leftn].right_neighbor=rightn; |
441 container[rightn].left_neighbor=leftn; |
490 container[rightn].left_neighbor=leftn; |
442 } |
491 } |
443 |
|
444 |
|
445 class store { |
|
446 friend class FibHeap; |
|
447 |
|
448 Item name; |
|
449 int parent; |
|
450 int left_neighbor; |
|
451 int right_neighbor; |
|
452 int child; |
|
453 int degree; |
|
454 bool marked; |
|
455 bool in; |
|
456 PrioType prio; |
|
457 |
|
458 store() : parent(-1), child(-1), degree(), marked(false), in(true) {} |
|
459 }; |
|
460 |
|
461 }; |
|
462 |
492 |
463 } //namespace hugo |
493 } //namespace hugo |
464 #endif |
494 #endif |