SparrowEngine/src/tools/fiboheap.h

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