├── sample.png ├── README.markdown ├── test.cpp └── fibonacci.hpp /sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinmessage/fibonacci/HEAD/sample.png -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Fibonacci Heap 2 | 3 | This is a simple fibonacci heap, supporting the standard operations: 4 | 5 | * Insert 6 | * Merge 7 | * Extract Minimum 8 | * Decrease Key 9 | 10 | We also have a non-standard *find* function; this is only for testing and should not be used in production as finding in a heap is O(n). 11 | 12 | Fibonacci heaps are slow and have significant storage overheads (4 pointers per node, plus an int and a bool for housekeeping.) They have a better complexity than binomial heaps only when you are doing significantly more merges or decrease key operations than extract minimum operations. 13 | 14 | This implementation should show how Fibonacci heaps work; it is not intended to be highly performant. 15 | 16 | ## Sample output 17 | The test program should produce a heap that looks like this: 18 | 19 | ![A diagram of a heap produced by this program](https://github.com/robinmessage/fibonacci/raw/master/sample.png "Sample Fibonacci Heap") 20 | 21 | Half-headed arrows are used for next and previous pointers. Full arrows are used for child and parent pointers. Filled arrowheads are used for next and child pointers; white arrowheads are for previous and parent pointers. Note that we synthesis child pointers to all the children of a node; in actuality, only one of these pointers is stored, since we can find sibling nodes. Marked nodes are grey and hoepfully the minimum is obvious. 22 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | /*Copyright (c) 2010, Robin Message 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the Univsersity of Cambridge nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF CAMBRIDGE OR ROBIN MESSAGE 19 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #include 25 | #include "fibonacci.hpp" 26 | 27 | //Add dotty output to our heap, which produces nice diagrams 28 | class DotFibonacciHeap : public FibonacciHeap { 29 | public: 30 | void dump() { 31 | printf("digraph G {\n"); 32 | if(heap==NULL) { 33 | printf("empty;\n}\n"); 34 | return; 35 | } 36 | printf("minimum -> \"%p\" [constraint=false];\n",heap); 37 | node* c=heap; 38 | do { 39 | _dumpChildren(c); 40 | c=c->getNext(); 41 | } while(c!=heap); 42 | printf("}\n"); 43 | } 44 | 45 | private: 46 | 47 | void _dumpChildren(node* n) { 48 | printf("\"%p\" -> \"%p\" [constraint=false,arrowhead=lnormal];\n",n,n->getNext()); 49 | printf("\"%p\" -> \"%p\" [constraint=false,arrowhead=ornormal];\n",n,n->getPrev()); 50 | if(n->isMarked())printf("\"%p\" [style=filled,fillcolor=grey];\n",n); 51 | if(n->hasParent()) { 52 | printf("\"%p\" -> \"%p\" [constraint=false,arrowhead=onormal];\n",n,n->getParent()); 53 | } 54 | printf("\"%p\" [label=%d];\n",n,n->getValue()); 55 | if(n->hasChildren()) { 56 | node* c=n->getChild(); 57 | do { 58 | printf("\"%p\" -> \"%p\";\n",n,c); 59 | _dumpChildren(c); 60 | c=c->getNext(); 61 | } while(c!=n->getChild()); 62 | } 63 | } 64 | }; 65 | 66 | 67 | void test() { 68 | DotFibonacciHeap h; 69 | h.insert(2); 70 | h.insert(3); 71 | h.insert(1); 72 | h.insert(4); 73 | h.removeMinimum(); 74 | h.removeMinimum(); 75 | h.insert(5); 76 | h.insert(7); 77 | h.removeMinimum(); 78 | h.insert(2); 79 | node* nine=h.insert(90); 80 | h.removeMinimum(); 81 | h.removeMinimum(); 82 | h.removeMinimum(); 83 | for(int i=0;i<20;i+=2)h.insert(30-i); 84 | for(int i=0;i<4;i++)h.removeMinimum(); 85 | for(int i=0;i<20;i+=2)h.insert(30-i); 86 | h.insert(23); 87 | for(int i=0;i<7;i++)h.removeMinimum(); 88 | h.decreaseKey(nine,1); 89 | h.decreaseKey(h.find(28),2); 90 | h.decreaseKey(h.find(23),3); 91 | 92 | h.dump(); 93 | } 94 | 95 | int main() { 96 | test(); 97 | } 98 | -------------------------------------------------------------------------------- /fibonacci.hpp: -------------------------------------------------------------------------------- 1 | /*Copyright (c) 2010, Robin Message 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the Univsersity of Cambridge nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF CAMBRIDGE OR ROBIN MESSAGE 19 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | template class FibonacciHeap; 25 | 26 | template struct node { 27 | private: 28 | node* prev; 29 | node* next; 30 | node* child; 31 | node* parent; 32 | V value; 33 | int degree; 34 | bool marked; 35 | public: 36 | friend class FibonacciHeap; 37 | node* getPrev() {return prev;} 38 | node* getNext() {return next;} 39 | node* getChild() {return child;} 40 | node* getParent() {return parent;} 41 | V getValue() {return value;} 42 | bool isMarked() {return marked;} 43 | 44 | bool hasChildren() {return child;} 45 | bool hasParent() {return parent;} 46 | }; 47 | 48 | template class FibonacciHeap { 49 | protected: 50 | node* heap; 51 | public: 52 | 53 | FibonacciHeap() { 54 | heap=_empty(); 55 | } 56 | virtual ~FibonacciHeap() { 57 | if(heap) { 58 | _deleteAll(heap); 59 | } 60 | } 61 | node* insert(V value) { 62 | node* ret=_singleton(value); 63 | heap=_merge(heap,ret); 64 | return ret; 65 | } 66 | void merge(FibonacciHeap& other) { 67 | heap=_merge(heap,other.heap); 68 | other.heap=_empty(); 69 | } 70 | 71 | bool isEmpty() { 72 | return heap==NULL; 73 | } 74 | 75 | V getMinimum() { 76 | return heap->value; 77 | } 78 | 79 | V removeMinimum() { 80 | node* old=heap; 81 | heap=_removeMinimum(heap); 82 | V ret=old->value; 83 | delete old; 84 | return ret; 85 | } 86 | 87 | void decreaseKey(node* n,V value) { 88 | heap=_decreaseKey(heap,n,value); 89 | } 90 | 91 | node* find(V value) { 92 | return _find(heap,value); 93 | } 94 | private: 95 | node* _empty() { 96 | return NULL; 97 | } 98 | 99 | node* _singleton(V value) { 100 | node* n=new node; 101 | n->value=value; 102 | n->prev=n->next=n; 103 | n->degree=0; 104 | n->marked=false; 105 | n->child=NULL; 106 | n->parent=NULL; 107 | return n; 108 | } 109 | 110 | node* _merge(node* a,node* b) { 111 | if(a==NULL)return b; 112 | if(b==NULL)return a; 113 | if(a->value>b->value) { 114 | node* temp=a; 115 | a=b; 116 | b=temp; 117 | } 118 | node* an=a->next; 119 | node* bp=b->prev; 120 | a->next=b; 121 | b->prev=a; 122 | an->prev=bp; 123 | bp->next=an; 124 | return a; 125 | } 126 | 127 | void _deleteAll(node* n) { 128 | if(n!=NULL) { 129 | node* c=n; 130 | do { 131 | node* d=c; 132 | c=c->next; 133 | _deleteAll(d->child); 134 | delete d; 135 | } while(c!=n); 136 | } 137 | } 138 | 139 | void _addChild(node* parent,node* child) { 140 | child->prev=child->next=child; 141 | child->parent=parent; 142 | parent->degree++; 143 | parent->child=_merge(parent->child,child); 144 | } 145 | 146 | void _unMarkAndUnParentAll(node* n) { 147 | if(n==NULL)return; 148 | node* c=n; 149 | do { 150 | c->marked=false; 151 | c->parent=NULL; 152 | c=c->next; 153 | }while(c!=n); 154 | } 155 | 156 | node* _removeMinimum(node* n) { 157 | _unMarkAndUnParentAll(n->child); 158 | if(n->next==n) { 159 | n=n->child; 160 | } else { 161 | n->next->prev=n->prev; 162 | n->prev->next=n->next; 163 | n=_merge(n->next,n->child); 164 | } 165 | if(n==NULL)return n; 166 | node* trees[64]={NULL}; 167 | 168 | while(true) { 169 | if(trees[n->degree]!=NULL) { 170 | node* t=trees[n->degree]; 171 | if(t==n)break; 172 | trees[n->degree]=NULL; 173 | if(n->valuevalue) { 174 | t->prev->next=t->next; 175 | t->next->prev=t->prev; 176 | _addChild(n,t); 177 | } else { 178 | t->prev->next=t->next; 179 | t->next->prev=t->prev; 180 | if(n->next==n) { 181 | t->next=t->prev=t; 182 | _addChild(t,n); 183 | n=t; 184 | } else { 185 | n->prev->next=t; 186 | n->next->prev=t; 187 | t->next=n->next; 188 | t->prev=n->prev; 189 | _addChild(t,n); 190 | n=t; 191 | } 192 | } 193 | continue; 194 | } else { 195 | trees[n->degree]=n; 196 | } 197 | n=n->next; 198 | } 199 | node* min=n; 200 | node* start=n; 201 | do { 202 | if(n->valuevalue)min=n; 203 | n=n->next; 204 | } while(n!=start); 205 | return min; 206 | } 207 | 208 | node* _cut(node* heap,node* n) { 209 | if(n->next==n) { 210 | n->parent->child=NULL; 211 | } else { 212 | n->next->prev=n->prev; 213 | n->prev->next=n->next; 214 | n->parent->child=n->next; 215 | } 216 | n->next=n->prev=n; 217 | n->marked=false; 218 | return _merge(heap,n); 219 | } 220 | 221 | node* _decreaseKey(node* heap,node* n,V value) { 222 | if(n->valuevalue=value; 224 | if(n->parent) { 225 | if(n->valueparent->value) { 226 | heap=_cut(heap,n); 227 | node* parent=n->parent; 228 | n->parent=NULL; 229 | while(parent!=NULL && parent->marked) { 230 | heap=_cut(heap,parent); 231 | n=parent; 232 | parent=n->parent; 233 | n->parent=NULL; 234 | } 235 | if(parent!=NULL && parent->parent!=NULL)parent->marked=true; 236 | } 237 | } else { 238 | if(n->value < heap->value) { 239 | heap = n; 240 | } 241 | } 242 | return heap; 243 | } 244 | 245 | node* _find(node* heap,V value) { 246 | node* n=heap; 247 | if(n==NULL)return NULL; 248 | do { 249 | if(n->value==value)return n; 250 | node* ret=_find(n->child,value); 251 | if(ret)return ret; 252 | n=n->next; 253 | }while(n!=heap); 254 | return NULL; 255 | } 256 | }; 257 | --------------------------------------------------------------------------------