3 #ifndef HUGO_FIB_HEAP_H
4 #define HUGO_FIB_HEAP_H
8 ///\brief Fibonacci Heap implementation.
16 /// \addtogroup auxdat
19 /// An implementation of the Fibonacci Heap.
22 This class implements the \e Fibonacci \e heap data structure. A \e heap
23 is a data structure for storing items with specified values called \e
24 priorities, such that finding the item with minimum priority with respect
25 to \e Compare is efficient. In a heap one can change the priority of an
26 item, add or erase an item, etc.
28 The methods \ref increase and \ref erase are not efficient in a Fibonacci
29 heap. In case of many calls to these operations, it is better to use a
32 \param Item The type of the items to be stored.
33 \param Prio The type of the priority of the items.
34 \param ItemIntMap A read and writable Item int map, for the usage of
36 \param Compare A class for the comparison of the priorities. The
37 default is \c std::less<Prio>.
42 template <typename Item,
47 template <typename Item,
50 typename Compare = std::less<Prio> >
54 typedef Prio PrioType;
59 std::vector<store> container;
65 ///\todo It is use nowhere
66 ///\todo It doesn't conform to the naming conventions.
74 FibHeap(ItemIntMap &_iimap) : minimum(0), iimap(_iimap), num_items() {}
75 FibHeap(ItemIntMap &_iimap, const Compare &_comp) : minimum(0),
76 iimap(_iimap), comp(_comp), num_items() {}
78 ///The number of items stored in the heap.
81 Returns the number of items stored in the heap.
83 int size() const { return num_items; }
85 ///Checks if the heap stores no items.
88 Returns \c true iff the heap stores no items.
90 bool empty() const { return num_items==0; }
92 ///\c item gets to the heap with priority \c value independently if \c item was already there.
95 This method calls \ref push(\c item, \c value) if \c item is not
96 stored in the heap and it calls \ref decrease(\c item, \c value) or
97 \ref increase(\c item, \c value) otherwise.
99 void set (Item const item, PrioType const value);
101 ///Adds \c item to the heap with priority \c value.
104 Adds \c item to the heap with priority \c value.
105 \pre \c item must not be stored in the heap.
107 void push (Item const item, PrioType const value);
110 ///Returns the item having the minimum priority w.r.t. Compare.
113 This method returns the item having the minimum priority w.r.t. Compare.
114 \pre The heap must be nonempty.
116 Item top() const { return container[minimum].name; }
119 ///Returns the minimum priority w.r.t. Compare.
122 It returns the minimum priority w.r.t. Compare.
123 \pre The heap must be nonempty.
125 PrioType prio() const { return container[minimum].prio; }
128 ///Returns the priority of \c item.
131 It returns the priority of \c item.
132 \pre \c item must be in the heap.
134 PrioType& operator[](const Item& item) {
135 return container[iimap[item]].prio;
138 ///Returns the priority of \c item.
141 It returns the priority of \c item.
142 \pre \c item must be in the heap.
144 const PrioType& operator[](const Item& item) const {
145 return container[iimap[item]].prio;
149 ///Deletes the item with minimum priority w.r.t. Compare.
152 This method deletes the item with minimum priority w.r.t.
153 Compare from the heap.
154 \pre The heap must be non-empty.
158 ///Deletes \c item from the heap.
161 This method deletes \c item from the heap, if \c item was already
162 stored in the heap. It is quite inefficient in Fibonacci heaps.
164 void erase (const Item& item);
166 ///Decreases the priority of \c item to \c value.
169 This method decreases the priority of \c item to \c value.
170 \pre \c item must be stored in the heap with priority at least \c
171 value w.r.t. Compare.
173 void decrease (Item item, PrioType const value);
176 ///Increases the priority of \c item to \c value.
179 This method sets the priority of \c item to \c value. Though
180 there is no precondition on the priority of \c item, this
181 method should be used only if there is a need to really \e increase
182 (w.r.t. Compare) the priority of \c item, because this
183 method is inefficient.
185 void increase (Item item, PrioType const value) {
191 ///Tells if \c item is in, was already in, or has never been in the heap.
194 This method returns PRE_HEAP if \c item has never been in the
195 heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
196 otherwise. In the latter case it is possible that \c item will
197 get back to the heap again.
199 state_enum state(const Item &item) const {
202 if ( container[i].in ) i=0;
205 return state_enum(i);
211 void makeroot(int c);
212 void cut(int a, int b);
214 void fuse(int a, int b);
219 friend class FibHeap;
231 store() : parent(-1), child(-1), degree(), marked(false), in(true) {}
237 // **********************************************************************
239 // **********************************************************************
241 template <typename Item, typename Prio, typename ItemIntMap,
243 void FibHeap<Item, Prio, ItemIntMap, Compare>::set
244 (Item const item, PrioType const value)
247 if ( i >= 0 && container[i].in ) {
248 if ( comp(value, container[i].prio) ) decrease(item, value);
249 if ( comp(container[i].prio, value) ) increase(item, value);
250 } else push(item, value);
253 template <typename Item, typename Prio, typename ItemIntMap,
255 void FibHeap<Item, Prio, ItemIntMap, Compare>::push
256 (Item const item, PrioType const value) {
259 int s=container.size();
260 iimap.set( item, s );
263 container.push_back(st);
266 container[i].parent=container[i].child=-1;
267 container[i].degree=0;
268 container[i].in=true;
269 container[i].marked=false;
273 container[container[minimum].right_neighbor].left_neighbor=i;
274 container[i].right_neighbor=container[minimum].right_neighbor;
275 container[minimum].right_neighbor=i;
276 container[i].left_neighbor=minimum;
277 if ( comp( value, container[minimum].prio) ) minimum=i;
279 container[i].right_neighbor=container[i].left_neighbor=i;
282 container[i].prio=value;
286 template <typename Item, typename Prio, typename ItemIntMap,
288 void FibHeap<Item, Prio, ItemIntMap, Compare>::pop() {
289 /*The first case is that there are only one root.*/
290 if ( container[minimum].left_neighbor==minimum ) {
291 container[minimum].in=false;
292 if ( container[minimum].degree!=0 ) {
293 makeroot(container[minimum].child);
294 minimum=container[minimum].child;
298 int right=container[minimum].right_neighbor;
300 container[minimum].in=false;
301 if ( container[minimum].degree > 0 ) {
302 int left=container[minimum].left_neighbor;
303 int child=container[minimum].child;
304 int last_child=container[child].left_neighbor;
308 container[left].right_neighbor=child;
309 container[child].left_neighbor=left;
310 container[right].left_neighbor=last_child;
311 container[last_child].right_neighbor=right;
315 } // the case where there are more roots
320 template <typename Item, typename Prio, typename ItemIntMap,
322 void FibHeap<Item, Prio, ItemIntMap, Compare>::erase
326 if ( i >= 0 && container[i].in ) {
327 if ( container[i].parent!=-1 ) {
328 int p=container[i].parent;
332 minimum=i; //As if its prio would be -infinity
337 template <typename Item, typename Prio, typename ItemIntMap,
339 void FibHeap<Item, Prio, ItemIntMap, Compare>::decrease
340 (Item item, PrioType const value) {
342 container[i].prio=value;
343 int p=container[i].parent;
345 if ( p!=-1 && comp(value, container[p].prio) ) {
349 if ( comp(value, container[minimum].prio) ) minimum=i;
353 template <typename Item, typename Prio, typename ItemIntMap,
355 void FibHeap<Item, Prio, ItemIntMap, Compare>::balance() {
357 int maxdeg=int( floor( 2.08*log(double(container.size()))))+1;
359 std::vector<int> A(maxdeg,-1);
362 *Recall that now minimum does not point to the minimum prio element.
363 *We set minimum to this during balance().
365 int anchor=container[minimum].left_neighbor;
371 if ( anchor==active ) end=true;
372 int d=container[active].degree;
373 next=container[active].right_neighbor;
376 if( comp(container[active].prio, container[A[d]].prio) ) {
389 while ( container[minimum].parent >=0 ) minimum=container[minimum].parent;
393 if ( comp(container[s].prio, container[minimum].prio) ) minimum=s;
394 s=container[s].right_neighbor;
398 template <typename Item, typename Prio, typename ItemIntMap,
400 void FibHeap<Item, Prio, ItemIntMap, Compare>::makeroot
404 container[s].parent=-1;
405 s=container[s].right_neighbor;
410 template <typename Item, typename Prio, typename ItemIntMap,
412 void FibHeap<Item, Prio, ItemIntMap, Compare>::cut
415 *Replacing a from the children of b.
417 --container[b].degree;
419 if ( container[b].degree !=0 ) {
420 int child=container[b].child;
422 container[b].child=container[child].right_neighbor;
427 /*Lacing a to the roots.*/
428 int right=container[minimum].right_neighbor;
429 container[minimum].right_neighbor=a;
430 container[a].left_neighbor=minimum;
431 container[a].right_neighbor=right;
432 container[right].left_neighbor=a;
434 container[a].parent=-1;
435 container[a].marked=false;
439 template <typename Item, typename Prio, typename ItemIntMap,
441 void FibHeap<Item, Prio, ItemIntMap, Compare>::cascade
444 if ( container[a].parent!=-1 ) {
445 int p=container[a].parent;
447 if ( container[a].marked==false ) container[a].marked=true;
456 template <typename Item, typename Prio, typename ItemIntMap,
458 void FibHeap<Item, Prio, ItemIntMap, Compare>::fuse
462 /*Lacing b under a.*/
463 container[b].parent=a;
465 if (container[a].degree==0) {
466 container[b].left_neighbor=b;
467 container[b].right_neighbor=b;
468 container[a].child=b;
470 int child=container[a].child;
471 int last_child=container[child].left_neighbor;
472 container[child].left_neighbor=b;
473 container[b].right_neighbor=child;
474 container[last_child].right_neighbor=b;
475 container[b].left_neighbor=last_child;
478 ++container[a].degree;
480 container[b].marked=false;
485 *It is invoked only if a has siblings.
487 template <typename Item, typename Prio, typename ItemIntMap,
489 void FibHeap<Item, Prio, ItemIntMap, Compare>::unlace
491 int leftn=container[a].left_neighbor;
492 int rightn=container[a].right_neighbor;
493 container[leftn].right_neighbor=rightn;
494 container[rightn].left_neighbor=leftn;