3 #ifndef HUGO_FIB_HEAP_H
4 #define HUGO_FIB_HEAP_H
7 ///\brief Fibonacci Heap implementation.
15 /// An implementation of the Fibonacci Heap.
18 This class implements the \e Fibonacci \e heap data structure. A \e heap
19 is a data structure for storing items with specified values called \e
20 priorities, such that finding the item with minimum priority with respect
21 to \e Compare is efficient. In a heap one can change the priority of an
22 item, add or erase an item, etc.
24 The methods \ref increase and \ref erase are not efficient in a Fibonacci
25 heap. In case of many calls to these operations, it is better to use a
28 \param Item The type of the items to be stored.
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
32 \param Compare A class for the comparison of the priorities. The
33 default is \c std::less<Prio>.
38 template <typename Item,
43 template <typename Item,
46 typename Compare = std::less<Prio> >
50 typedef Prio PrioType;
55 std::vector<store> container;
61 ///\todo It is use nowhere
62 ///\todo It doesn't conform to the naming conventions.
70 FibHeap(ItemIntMap &_iimap) : minimum(0), iimap(_iimap), num_items() {}
71 FibHeap(ItemIntMap &_iimap, const Compare &_comp) : minimum(0),
72 iimap(_iimap), comp(_comp), num_items() {}
74 ///The number of items stored in the heap.
77 Returns the number of items stored in the heap.
79 int size() const { return num_items; }
81 ///Checks if the heap stores no items.
84 Returns \c true iff the heap stores no items.
86 bool empty() const { return num_items==0; }
88 ///\c item gets to the heap with priority \c value independently if \c item was already there.
91 This method calls \ref push(\c item, \c value) if \c item is not
92 stored in the heap and it calls \ref decrease(\c item, \c value) or
93 \ref increase(\c item, \c value) otherwise.
95 void set (Item const item, PrioType const value);
97 ///Adds \c item to the heap with priority \c value.
100 Adds \c item to the heap with priority \c value.
101 \pre \c item must not be stored in the heap.
103 void push (Item const item, PrioType const value);
106 ///Returns the item having the minimum priority w.r.t. Compare.
109 This method returns the item having the minimum priority w.r.t. Compare.
110 \pre The heap must be nonempty.
112 Item top() const { return container[minimum].name; }
115 ///Returns the minimum priority w.r.t. Compare.
118 It returns the minimum priority w.r.t. Compare.
119 \pre The heap must be nonempty.
121 PrioType prio() const { return container[minimum].prio; }
124 ///Returns the priority of \c item.
127 It returns the priority of \c item.
128 \pre \c item must be in the heap.
130 PrioType& operator[](const Item& item) {
131 return container[iimap[item]].prio;
134 ///Returns the priority of \c item.
137 It returns the priority of \c item.
138 \pre \c item must be in the heap.
140 const PrioType& operator[](const Item& item) const {
141 return container[iimap[item]].prio;
145 ///Deletes the item with minimum priority w.r.t. Compare.
148 This method deletes the item with minimum priority w.r.t.
149 Compare from the heap.
150 \pre The heap must be non-empty.
154 ///Deletes \c item from the heap.
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.
160 void erase (const Item& item);
162 ///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
167 value w.r.t. Compare.
169 void decrease (Item item, PrioType const value);
172 ///Increases the priority of \c item to \c value.
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
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
179 method is inefficient.
181 void increase (Item item, PrioType const value) {
187 ///Tells if \c item is in, was already in, or has never been in the heap.
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
192 otherwise. In the latter case it is possible that \c item will
193 get back to the heap again.
195 state_enum state(const Item &item) const {
198 if ( container[i].in ) i=0;
201 return state_enum(i);
207 void makeroot(int c);
208 void cut(int a, int b);
210 void fuse(int a, int b);
215 friend class FibHeap;
227 store() : parent(-1), child(-1), degree(), marked(false), in(true) {}
233 // **********************************************************************
235 // **********************************************************************
237 template <typename Item, typename Prio, typename ItemIntMap,
239 void FibHeap<Item, Prio, ItemIntMap, Compare>::set
240 (Item const item, PrioType const value)
243 if ( i >= 0 && container[i].in ) {
244 if ( comp(value, container[i].prio) ) decrease(item, value);
245 if ( comp(container[i].prio, value) ) increase(item, value);
246 } else push(item, value);
249 template <typename Item, typename Prio, typename ItemIntMap,
251 void FibHeap<Item, Prio, ItemIntMap, Compare>::push
252 (Item const item, PrioType const value) {
255 int s=container.size();
256 iimap.set( item, s );
259 container.push_back(st);
262 container[i].parent=container[i].child=-1;
263 container[i].degree=0;
264 container[i].in=true;
265 container[i].marked=false;
269 container[container[minimum].right_neighbor].left_neighbor=i;
270 container[i].right_neighbor=container[minimum].right_neighbor;
271 container[minimum].right_neighbor=i;
272 container[i].left_neighbor=minimum;
273 if ( comp( value, container[minimum].prio) ) minimum=i;
275 container[i].right_neighbor=container[i].left_neighbor=i;
278 container[i].prio=value;
282 template <typename Item, typename Prio, typename ItemIntMap,
284 void FibHeap<Item, Prio, ItemIntMap, Compare>::pop() {
285 /*The first case is that there are only one root.*/
286 if ( container[minimum].left_neighbor==minimum ) {
287 container[minimum].in=false;
288 if ( container[minimum].degree!=0 ) {
289 makeroot(container[minimum].child);
290 minimum=container[minimum].child;
294 int right=container[minimum].right_neighbor;
296 container[minimum].in=false;
297 if ( container[minimum].degree > 0 ) {
298 int left=container[minimum].left_neighbor;
299 int child=container[minimum].child;
300 int last_child=container[child].left_neighbor;
304 container[left].right_neighbor=child;
305 container[child].left_neighbor=left;
306 container[right].left_neighbor=last_child;
307 container[last_child].right_neighbor=right;
311 } // the case where there are more roots
316 template <typename Item, typename Prio, typename ItemIntMap,
318 void FibHeap<Item, Prio, ItemIntMap, Compare>::erase
322 if ( i >= 0 && container[i].in ) {
323 if ( container[i].parent!=-1 ) {
324 int p=container[i].parent;
328 minimum=i; //As if its prio would be -infinity
333 template <typename Item, typename Prio, typename ItemIntMap,
335 void FibHeap<Item, Prio, ItemIntMap, Compare>::decrease
336 (Item item, PrioType const value) {
338 container[i].prio=value;
339 int p=container[i].parent;
341 if ( p!=-1 && comp(value, container[p].prio) ) {
345 if ( comp(value, container[minimum].prio) ) minimum=i;
349 template <typename Item, typename Prio, typename ItemIntMap,
351 void FibHeap<Item, Prio, ItemIntMap, Compare>::balance() {
353 int maxdeg=int( floor( 2.08*log(double(container.size()))))+1;
355 std::vector<int> A(maxdeg,-1);
358 *Recall that now minimum does not point to the minimum prio element.
359 *We set minimum to this during balance().
361 int anchor=container[minimum].left_neighbor;
367 if ( anchor==active ) end=true;
368 int d=container[active].degree;
369 next=container[active].right_neighbor;
372 if( comp(container[active].prio, container[A[d]].prio) ) {
385 while ( container[minimum].parent >=0 ) minimum=container[minimum].parent;
389 if ( comp(container[s].prio, container[minimum].prio) ) minimum=s;
390 s=container[s].right_neighbor;
394 template <typename Item, typename Prio, typename ItemIntMap,
396 void FibHeap<Item, Prio, ItemIntMap, Compare>::makeroot
400 container[s].parent=-1;
401 s=container[s].right_neighbor;
406 template <typename Item, typename Prio, typename ItemIntMap,
408 void FibHeap<Item, Prio, ItemIntMap, Compare>::cut
411 *Replacing a from the children of b.
413 --container[b].degree;
415 if ( container[b].degree !=0 ) {
416 int child=container[b].child;
418 container[b].child=container[child].right_neighbor;
423 /*Lacing a to the roots.*/
424 int right=container[minimum].right_neighbor;
425 container[minimum].right_neighbor=a;
426 container[a].left_neighbor=minimum;
427 container[a].right_neighbor=right;
428 container[right].left_neighbor=a;
430 container[a].parent=-1;
431 container[a].marked=false;
435 template <typename Item, typename Prio, typename ItemIntMap,
437 void FibHeap<Item, Prio, ItemIntMap, Compare>::cascade
440 if ( container[a].parent!=-1 ) {
441 int p=container[a].parent;
443 if ( container[a].marked==false ) container[a].marked=true;
452 template <typename Item, typename Prio, typename ItemIntMap,
454 void FibHeap<Item, Prio, ItemIntMap, Compare>::fuse
458 /*Lacing b under a.*/
459 container[b].parent=a;
461 if (container[a].degree==0) {
462 container[b].left_neighbor=b;
463 container[b].right_neighbor=b;
464 container[a].child=b;
466 int child=container[a].child;
467 int last_child=container[child].left_neighbor;
468 container[child].left_neighbor=b;
469 container[b].right_neighbor=child;
470 container[last_child].right_neighbor=b;
471 container[b].left_neighbor=last_child;
474 ++container[a].degree;
476 container[b].marked=false;
481 *It is invoked only if a has siblings.
483 template <typename Item, typename Prio, typename ItemIntMap,
485 void FibHeap<Item, Prio, ItemIntMap, Compare>::unlace
487 int leftn=container[a].left_neighbor;
488 int rightn=container[a].right_neighbor;
489 container[leftn].right_neighbor=rightn;
490 container[rightn].left_neighbor=leftn;