579 lines
11 KiB
C++
579 lines
11 KiB
C++
/**
|
|
* Fibonacci Heap
|
|
* Copyright (c) 2014, Emmanuel Benazera beniz@droidnik.fr, All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 3.0 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library.
|
|
*/
|
|
|
|
#ifndef FIBOHEAP_H
|
|
#define FIBOHEAP_H
|
|
|
|
#include <cstddef>
|
|
#include <math.h>
|
|
#include <limits>
|
|
#include <iostream>
|
|
|
|
template<class T>
|
|
class FibHeap
|
|
{
|
|
public:
|
|
|
|
// node
|
|
class FibNode
|
|
{
|
|
public:
|
|
FibNode(T k, void *pl)
|
|
:key(k),mark(false),p(nullptr),left(nullptr),right(nullptr),child(nullptr),degree(-1),payload(pl)
|
|
{
|
|
}
|
|
|
|
~FibNode()
|
|
{
|
|
}
|
|
|
|
T key;
|
|
bool mark;
|
|
FibNode *p;
|
|
FibNode *left;
|
|
FibNode *right;
|
|
FibNode *child;
|
|
int degree;
|
|
void *payload;
|
|
}; // end FibNode
|
|
|
|
FibHeap()
|
|
:n(0),min(nullptr)
|
|
{
|
|
}
|
|
|
|
~FibHeap()
|
|
{
|
|
// delete all nodes.
|
|
delete_fibnodes(min);
|
|
}
|
|
|
|
void delete_fibnodes(FibNode *x)
|
|
{
|
|
if (!x)
|
|
return;
|
|
|
|
FibNode *cur = x;
|
|
while(true)
|
|
{
|
|
/*std::cerr << "cur: " << cur << std::endl;
|
|
std::cerr << "x: " << x << std::endl;*/
|
|
if (cur->left && cur->left != x)
|
|
{
|
|
//std::cerr << "cur left: " << cur->left << std::endl;
|
|
FibNode *tmp = cur;
|
|
cur = cur->left;
|
|
if (tmp->child)
|
|
delete_fibnodes(tmp->child);
|
|
delete tmp;
|
|
}
|
|
else
|
|
{
|
|
if (cur->child)
|
|
delete_fibnodes(cur->child);
|
|
delete cur;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* insert(x)
|
|
* 1. x.degree = 0
|
|
* 2. x.p = NIL
|
|
* 3. x.child = NIL
|
|
* 4. x.mark = FALSE
|
|
* 5. if H.min == NIL
|
|
* 6. create a root list for H containing just x
|
|
* 7. H.min = x
|
|
* 8. else insert x into H's root list
|
|
* 9. if x.key < H.min.key
|
|
*10. H.min = x
|
|
*11. H.n = H.n + 1
|
|
*/
|
|
void insert(FibNode *x)
|
|
{
|
|
// 1
|
|
x->degree = 0;
|
|
// 2
|
|
x->p = nullptr;
|
|
// 3
|
|
x->child = nullptr;
|
|
// 4
|
|
x->mark = false;
|
|
// 5
|
|
if ( min == nullptr)
|
|
{
|
|
// 6, 7
|
|
min = x->left = x->right = x;
|
|
}
|
|
else
|
|
{
|
|
// 8
|
|
min->left->right = x;
|
|
x->left = min->left;
|
|
min->left = x;
|
|
x->right = min;
|
|
// 9
|
|
if ( x->key < min->key )
|
|
{
|
|
// 10
|
|
min = x;
|
|
}
|
|
}
|
|
// 11
|
|
++n;
|
|
}
|
|
|
|
/*
|
|
* The minimum node of the heap.
|
|
*/
|
|
FibNode* minimum()
|
|
{
|
|
return min;
|
|
}
|
|
|
|
/*
|
|
* union_fibheap(H1,H2)
|
|
* 1. H = MAKE-FIB-HEAP()
|
|
* 2. H.min = H1.min
|
|
* 3. concatenate the root list of H2 with the root list of H
|
|
* 4. if (H1.min == NIL) or (H2.min != NIL and H2.min.key < H1.min.key)
|
|
* 5. H.min = H2.min
|
|
* 6. H.n = H1.n + H2.n
|
|
* 7. return H
|
|
*/
|
|
static FibHeap* union_fibheap(FibHeap *H1, FibHeap *H2)
|
|
{
|
|
// 1
|
|
FibHeap* H = new FibHeap();
|
|
// 2
|
|
H->min = H1->min;
|
|
// 3
|
|
if ( H->min != nullptr && H2->min != nullptr )
|
|
{
|
|
H->min->right->left = H2->min->left;
|
|
H2->min->left->right = H->min->right;
|
|
H->min->right = H2->min;
|
|
H2->min->left = H->min;
|
|
}
|
|
// 4
|
|
if ( H1->min == nullptr || ( H2->min != nullptr && H2->min->key < H1->min->key ) )
|
|
{
|
|
// 5
|
|
H->min = H2->min;
|
|
}
|
|
// 6
|
|
H->n = H1->n + H2->n;
|
|
// 7
|
|
return H;
|
|
}
|
|
|
|
/*
|
|
* extract_min
|
|
* 1. z = H.min
|
|
* 2. if z != NIL
|
|
* 3. for each child x of z
|
|
* 4. add x to the root list of H
|
|
* 5. x.p = NIL
|
|
* 6. remove z from the root list of H
|
|
* 7. if z == z.right
|
|
* 8. H.min = NIL
|
|
* 9. else H.min = z.right
|
|
*10. CONSOLIDATE(H)
|
|
*11. H.n = H.n - 1
|
|
*12. return z
|
|
*/
|
|
FibNode* extract_min()
|
|
{
|
|
FibNode *z, *x, *next;
|
|
FibNode ** childList;
|
|
|
|
// 1
|
|
z = min;
|
|
// 2
|
|
if ( z != nullptr )
|
|
{
|
|
// 3
|
|
x = z->child;
|
|
if ( x != nullptr )
|
|
{
|
|
childList = new FibNode*[z->degree];
|
|
next = x;
|
|
for ( int i = 0; i < (int)z->degree; i++ )
|
|
{
|
|
childList[i] = next;
|
|
next = next->right;
|
|
}
|
|
for ( int i = 0; i < (int)z->degree; i++ )
|
|
{
|
|
x = childList[i];
|
|
// 4
|
|
min->left->right = x;
|
|
x->left = min->left;
|
|
min->left = x;
|
|
x->right = min;
|
|
// 5
|
|
x->p = nullptr;
|
|
}
|
|
delete [] childList;
|
|
}
|
|
// 6
|
|
z->left->right = z->right;
|
|
z->right->left = z->left;
|
|
// 7
|
|
if ( z == z->right )
|
|
{
|
|
// 8
|
|
min = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// 9
|
|
min = z->right;
|
|
// 10
|
|
consolidate();
|
|
}
|
|
// 11
|
|
n--;
|
|
}
|
|
// 12
|
|
return z;
|
|
}
|
|
|
|
/*
|
|
* consolidate
|
|
* 1. let A[0 . . D(H.n)] be a new array
|
|
* 2. for i = 0 to D(H.n)
|
|
* 3. A[i] = NIL
|
|
* 4. for each node w in the root list of H
|
|
* 5. x = w
|
|
* 6. d = x.degree
|
|
* 7. while A[d] != NIL
|
|
* 8. y = A[d]
|
|
* 9. if x.key > y.key
|
|
*10. exchange x with y
|
|
*11. FIB-HEAP-LINK(H,y,x)
|
|
*12. A[d] = NIL
|
|
*13. d = d + 1
|
|
*14. A[d] = x
|
|
*15. H.min = NIL
|
|
*16. for i = 0 to D(H.n)
|
|
*17. if A[i] != NIL
|
|
*18. if H.min == NIL
|
|
*19. create a root list for H containing just A[i]
|
|
*20. H.min = A[i]
|
|
*21. else insert A[i] into H's root list
|
|
*22. if A[i].key < H.min.key
|
|
*23. H.min = A[i]
|
|
*/
|
|
void consolidate()
|
|
{
|
|
FibNode* w, * next, * x, * y, * temp;
|
|
FibNode** A, ** rootList;
|
|
// Max degree <= log base golden ratio of n
|
|
int d, rootSize;
|
|
int max_degree = static_cast<int>(floor(log(static_cast<double>(n))/log(static_cast<double>(1 + sqrt(static_cast<double>(5)))/2)));
|
|
|
|
// 1
|
|
A = new FibNode*[max_degree+2]; // plus two both for indexing to max degree and so A[max_degree+1] == NIL
|
|
// 2, 3
|
|
std::fill_n(A, max_degree+2, nullptr);
|
|
// 4
|
|
w = min;
|
|
rootSize = 0;
|
|
next = w;
|
|
do
|
|
{
|
|
rootSize++;
|
|
next = next->right;
|
|
} while ( next != w );
|
|
rootList = new FibNode*[rootSize];
|
|
for ( int i = 0; i < rootSize; i++ )
|
|
{
|
|
rootList[i] = next;
|
|
next = next->right;
|
|
}
|
|
for ( int i = 0; i < rootSize; i++ )
|
|
{
|
|
w = rootList[i];
|
|
// 5
|
|
x = w;
|
|
// 6
|
|
d = x->degree;
|
|
// 7
|
|
while ( A[d] != nullptr )
|
|
{
|
|
// 8
|
|
y = A[d];
|
|
// 9
|
|
if ( x->key > y->key )
|
|
{
|
|
// 10
|
|
temp = x;
|
|
x = y;
|
|
y = temp;
|
|
}
|
|
// 11
|
|
fib_heap_link(y,x);
|
|
// 12
|
|
A[d] = nullptr;
|
|
// 13
|
|
d++;
|
|
}
|
|
// 14
|
|
A[d] = x;
|
|
}
|
|
delete [] rootList;
|
|
// 15
|
|
min = nullptr;
|
|
// 16
|
|
for ( int i = 0; i < max_degree+2; i++ )
|
|
{
|
|
// 17
|
|
if ( A[i] != nullptr )
|
|
{
|
|
// 18
|
|
if ( min == nullptr )
|
|
{
|
|
// 19, 20
|
|
min = A[i]->left = A[i]->right = A[i];
|
|
}
|
|
else
|
|
{
|
|
// 21
|
|
min->left->right = A[i];
|
|
A[i]->left = min->left;
|
|
min->left = A[i];
|
|
A[i]->right = min;
|
|
// 22
|
|
if ( A[i]->key < min->key )
|
|
{
|
|
// 23
|
|
min = A[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
delete [] A;
|
|
}
|
|
|
|
/*
|
|
* fib_heap_link(y,x)
|
|
* 1. remove y from the root list of heap
|
|
* 2. make y a child of x, incrementing x.degree
|
|
* 3. y.mark = FALSE
|
|
*/
|
|
void fib_heap_link( FibNode* y, FibNode* x )
|
|
{
|
|
// 1
|
|
y->left->right = y->right;
|
|
y->right->left = y->left;
|
|
// 2
|
|
if ( x->child != nullptr )
|
|
{
|
|
x->child->left->right = y;
|
|
y->left = x->child->left;
|
|
x->child->left = y;
|
|
y->right = x->child;
|
|
}
|
|
else
|
|
{
|
|
x->child = y;
|
|
y->right = y;
|
|
y->left = y;
|
|
}
|
|
y->p = x;
|
|
x->degree++;
|
|
// 3
|
|
y->mark = false;
|
|
}
|
|
|
|
|
|
/*
|
|
* decrease_key(x,k)
|
|
* 1. if k > x.key
|
|
* 2. error "new key is greater than current key"
|
|
* 3. x.key = k
|
|
* 4. y = x.p
|
|
* 5. if y != NIL and x.key < y.key
|
|
* 6. CUT(H,x,y)
|
|
* 7. CASCADING-CUT(H,y)
|
|
* 8. if x.key < H.min.key
|
|
* 9. H.min = x
|
|
*/
|
|
void decrease_key( FibNode* x, int k )
|
|
{
|
|
FibNode* y;
|
|
|
|
// 1
|
|
if ( k > x->key )
|
|
{
|
|
// 2
|
|
// error( "new key is greater than current key" );
|
|
return;
|
|
}
|
|
// 3
|
|
x->key = k;
|
|
// 4
|
|
y = x->p;
|
|
// 5
|
|
if ( y != nullptr && x->key < y->key )
|
|
{
|
|
// 6
|
|
cut(x,y);
|
|
// 7
|
|
cascading_cut(y);
|
|
}
|
|
// 8
|
|
if ( x->key < min->key )
|
|
{
|
|
// 9
|
|
min = x;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* cut(x,y)
|
|
* 1. remove x from the child list of y, decrementing y.degree
|
|
* 2. add x to the root list of H
|
|
* 3. x.p = NIL
|
|
* 4. x.mark = FALSE
|
|
*/
|
|
void cut( FibNode* x, FibNode* y )
|
|
{
|
|
// 1
|
|
if ( x->right == x )
|
|
{
|
|
y->child = nullptr;
|
|
}
|
|
else
|
|
{
|
|
x->right->left = x->left;
|
|
x->left->right = x->right;
|
|
if ( y->child == x )
|
|
{
|
|
y->child = x->right;
|
|
}
|
|
}
|
|
y->degree--;
|
|
// 2
|
|
min->right->left = x;
|
|
x->right = min->right;
|
|
min->right = x;
|
|
x->left = min;
|
|
// 3
|
|
x->p = nullptr;
|
|
// 4
|
|
x->mark = false;
|
|
}
|
|
|
|
/*
|
|
* cascading_cut(y)
|
|
* 1. z = y.p
|
|
* 2. if z != NIL
|
|
* 3. if y.mark == FALSE
|
|
* 4. y.mark = TRUE
|
|
* 5. else CUT(H,y,z)
|
|
* 6. CASCADING-CUT(H,z)
|
|
*/
|
|
void cascading_cut( FibNode* y )
|
|
{
|
|
FibNode* z;
|
|
|
|
// 1
|
|
z = y->p;
|
|
// 2
|
|
if ( z != nullptr )
|
|
{
|
|
// 3
|
|
if ( y->mark == false )
|
|
{
|
|
// 4
|
|
y->mark = true;
|
|
}
|
|
else
|
|
{
|
|
// 5
|
|
cut(y,z);
|
|
// 6
|
|
cascading_cut(z);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* set to infinity so that it hits the top of the heap, then easily remove.
|
|
*/
|
|
void remove_fibnode( FibNode* x )
|
|
{
|
|
decrease_key(x,std::numeric_limits<T>::min());
|
|
FibNode *fn = extract_min();
|
|
delete fn;
|
|
}
|
|
|
|
/*
|
|
* mapping operations to STL-compatible signatures.
|
|
*/
|
|
bool empty() const
|
|
{
|
|
return n == 0;
|
|
}
|
|
|
|
FibNode* topNode()
|
|
{
|
|
return minimum();
|
|
}
|
|
|
|
T top()
|
|
{
|
|
return minimum()->key;
|
|
}
|
|
|
|
void pop()
|
|
{
|
|
if (empty())
|
|
return;
|
|
FibNode *x = extract_min();
|
|
if (x)
|
|
delete x;
|
|
}
|
|
|
|
FibNode* push(T k, void *pl)
|
|
{
|
|
FibNode *x = new FibNode(k,pl);
|
|
insert(x);
|
|
return x;
|
|
}
|
|
|
|
FibNode* push(T k)
|
|
{
|
|
return push(k,nullptr);
|
|
}
|
|
|
|
unsigned int size()
|
|
{
|
|
return (unsigned int) n;
|
|
}
|
|
|
|
int n;
|
|
FibNode *min;
|
|
|
|
};
|
|
#endif
|