344 lines
8.3 KiB
C++
344 lines
8.3 KiB
C++
#include <iostream>
|
|
#include <vector>
|
|
#include <cmath>
|
|
|
|
/**
|
|
* Heap operation are defined with node pointer to allow
|
|
* decrease key to be called with the given node.
|
|
*/
|
|
|
|
|
|
struct Node
|
|
{
|
|
int key;
|
|
int degree;
|
|
bool mark;
|
|
int data; // an extra field, not required for implementation
|
|
Node* left;
|
|
Node* right;
|
|
Node* parent;
|
|
Node* child;
|
|
|
|
Node(int key): key(key){};
|
|
Node(int key, int data): key(key), data(data){};
|
|
|
|
friend std::ostream& operator<<(std::ostream& os, const Node &n){
|
|
os << "{ "
|
|
<< "key: " << n.key << " ; "
|
|
<< "degree: " << n.degree << "; "
|
|
<< "mark: " << n.mark << "; "
|
|
<< "data: " << n.data << "; "
|
|
<< "left: " << (n.left == nullptr? -1: n.left->data) << "; "
|
|
<< "right: " << (n.right == nullptr? -1: n.right->data) << "; "
|
|
<< "parent: " << (n.parent == nullptr? -1: n.parent->data) << "; "
|
|
<< "child: " << (n.child == nullptr? -1: n.child->data) << "; "
|
|
<< " }";
|
|
|
|
return os;
|
|
}
|
|
};
|
|
|
|
class FibonacciHeap
|
|
{
|
|
private:
|
|
Node* _mn;
|
|
int _length;
|
|
|
|
/**
|
|
* @brief inserts a node to rootlist after given node
|
|
*
|
|
* @param after
|
|
* @param toInsert
|
|
*/
|
|
void _insertTORootListAfterNode(Node *after, Node *toInsert){
|
|
if(after->right == after){
|
|
//after ----> after toInsert
|
|
toInsert->right = toInsert->left = after;
|
|
after->right = after->left = toInsert;
|
|
return ;
|
|
}
|
|
// after next
|
|
// after toInsert next
|
|
toInsert->left = after;
|
|
toInsert->right = after->right;
|
|
|
|
toInsert->left->right = toInsert;
|
|
toInsert->right->left = toInsert;
|
|
}
|
|
|
|
/**
|
|
* @brief removes the given node from rootlist
|
|
* but it still contains reference to its neighbours
|
|
*
|
|
* @param toDelete
|
|
* @return Node*
|
|
*/
|
|
Node* _removeNodeFromRootList(Node *toDelete){
|
|
auto left = toDelete->left;
|
|
|
|
if(toDelete == left) // only one child left
|
|
left = nullptr;
|
|
else if(toDelete->right == toDelete->left){ // only two child left
|
|
// cld left ---> left
|
|
left->left = left;
|
|
left->right = left;
|
|
}
|
|
else{ // if at least three child is there
|
|
// left cld right
|
|
// left right
|
|
toDelete->left->right = toDelete->right;
|
|
toDelete->right->left = toDelete->left;
|
|
}
|
|
|
|
toDelete->parent = nullptr;
|
|
return left;
|
|
}
|
|
|
|
/**
|
|
* @brief inserts all child node of parent node to same rootlist
|
|
* the parent exists
|
|
*
|
|
* @param parent
|
|
*/
|
|
void _insertChildOfNodeToRootList(Node* parent){
|
|
for(auto cld = parent->child; cld != nullptr;){
|
|
auto left = _removeNodeFromRootList(cld);
|
|
_insertTORootListAfterNode(parent, cld);
|
|
cld = left;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief inserts a new child at root list after insertAt
|
|
*
|
|
* @param insertAt
|
|
* @param toInsert
|
|
* @return Node* insertAt node is changed in the function call
|
|
* so it is recommanded to assign to the return value;
|
|
*/
|
|
Node* _insertNewChildAtRootList(Node* insertAt, Node* toInsert){
|
|
if(insertAt == nullptr){
|
|
insertAt = toInsert;
|
|
insertAt->right = toInsert;
|
|
insertAt->left = toInsert;
|
|
}
|
|
else{
|
|
_insertTORootListAfterNode(insertAt, toInsert);
|
|
}
|
|
|
|
return insertAt;
|
|
}
|
|
|
|
/**
|
|
* @brief links child a children of parent and performs
|
|
* associated links
|
|
*
|
|
* @param parent
|
|
* @param child
|
|
* @return Node*
|
|
*/
|
|
Node* _fibHeapLink(Node* parent, Node* child){
|
|
_removeNodeFromRootList(child);
|
|
|
|
child->parent = parent;
|
|
parent->child = _insertNewChildAtRootList(parent->child, child);
|
|
|
|
child->mark = false;
|
|
parent->degree ++;
|
|
|
|
return parent;
|
|
}
|
|
|
|
/**
|
|
* @brief consolidates the fibonacchi heap
|
|
*
|
|
*/
|
|
void _consolidate(){
|
|
std::vector<Node *> roots;
|
|
roots.push_back(_mn);
|
|
for(auto cur = _mn->right; cur != _mn ;cur = cur->right){
|
|
roots.push_back(cur);
|
|
}
|
|
|
|
int upper_bound = log2(_length) + 2;
|
|
std::vector<Node *> array(upper_bound, nullptr);
|
|
for(auto cur : roots){
|
|
auto z = cur;
|
|
int d = cur->degree;
|
|
while(array[d] != nullptr){
|
|
auto y = array[d];
|
|
|
|
if(z->key <= y->key) z = _fibHeapLink(z, y);
|
|
else z = _fibHeapLink(y, z);
|
|
|
|
array[d] = nullptr;
|
|
|
|
d++;
|
|
}
|
|
|
|
array[d] = z;
|
|
}
|
|
|
|
_mn = nullptr;
|
|
for(auto node: array){
|
|
if(node == nullptr) continue;
|
|
|
|
_mn = _insertNewChildAtRootList(_mn, node);
|
|
if(_mn->key > node->key){
|
|
_mn = node;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void _cut(Node* parent, Node* node){
|
|
parent->child = _removeNodeFromRootList(node);
|
|
if(parent->child)
|
|
parent->child->parent = parent;
|
|
parent->degree--;
|
|
|
|
_insertTORootListAfterNode(_mn, node);
|
|
node->parent = nullptr;
|
|
node->mark = false;
|
|
}
|
|
|
|
void _cascadingCut(Node* parent){
|
|
auto grandP = parent->parent;
|
|
if(grandP != nullptr){
|
|
if(parent->mark == false) parent->mark = true;
|
|
else {
|
|
_cut(grandP, parent);
|
|
_cascadingCut(grandP);
|
|
}
|
|
}
|
|
}
|
|
|
|
void _printHelper(std::ostream& os, Node *n, int tab){
|
|
if(n == nullptr) return ;
|
|
|
|
for(int i = 0; i < tab; i++) os << "\t";
|
|
os << *n << std::endl;
|
|
_printHelper(os, n->child, tab+1);
|
|
|
|
for(auto cur = n->right; cur != n; cur = cur->right){
|
|
for(int i = 0; i < tab; i++) os << "\t";
|
|
os << *cur << std::endl;
|
|
_printHelper(os, cur->child, tab+1);
|
|
}
|
|
}
|
|
|
|
public:
|
|
FibonacciHeap(/* args */);
|
|
~FibonacciHeap();
|
|
|
|
void insert(Node *toInsert){
|
|
toInsert->degree = 0;
|
|
toInsert->mark = false;
|
|
toInsert->parent = nullptr;
|
|
toInsert->child = nullptr;
|
|
|
|
_mn = _insertNewChildAtRootList(_mn, toInsert);
|
|
if(_mn->key > toInsert->key){
|
|
_mn = toInsert;
|
|
}
|
|
|
|
_length++;
|
|
}
|
|
|
|
void pop(){
|
|
if(_mn != nullptr){
|
|
_insertChildOfNodeToRootList(_mn);
|
|
_removeNodeFromRootList(_mn);
|
|
|
|
if(_mn->left == _mn){
|
|
_mn = nullptr;
|
|
}else{
|
|
_mn = _mn->right;
|
|
_consolidate();
|
|
}
|
|
|
|
_length--;
|
|
}
|
|
}
|
|
|
|
Node* top(){
|
|
return _mn;
|
|
}
|
|
|
|
int length(){
|
|
return _length;
|
|
}
|
|
|
|
void decreaseKey(Node* node, int k){
|
|
if(node->key <= k) {
|
|
std::cerr << "node->key <= k" << std::endl;;
|
|
return ;
|
|
}
|
|
|
|
node->key = k;
|
|
auto parent = node->parent;
|
|
if(parent != nullptr && node->key < parent->key){
|
|
_cut(parent, node);
|
|
_cascadingCut(parent);
|
|
}
|
|
|
|
if(node->key < _mn->key){
|
|
_mn = node;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
friend std::ostream& operator<<(std::ostream& os, FibonacciHeap &f){
|
|
os << "====================================================" << std::endl;
|
|
|
|
if(f._mn == nullptr) os << "null" << std::endl;
|
|
os << "length : " << f._length << std::endl;
|
|
|
|
f._printHelper(os, f._mn, 0);
|
|
|
|
os << "====================================================" << std::endl;
|
|
return os;
|
|
}
|
|
};
|
|
|
|
FibonacciHeap::FibonacciHeap(/* args */)
|
|
{
|
|
_mn = nullptr;
|
|
_length = 0;
|
|
}
|
|
|
|
FibonacciHeap::~FibonacciHeap()
|
|
{
|
|
}
|
|
|
|
|
|
int main(int argc, char const *argv[])
|
|
{
|
|
FibonacciHeap fh;
|
|
Node *node1 = new Node(10, 5);
|
|
Node *node2 = new Node(20, 5);
|
|
Node *node3 = new Node(30, 5);
|
|
|
|
fh.insert(node1);
|
|
fh.insert(node2);
|
|
fh.insert(node3);
|
|
|
|
std::cout << fh << std::endl;
|
|
std::cout << "Top : " << *fh.top() << std::endl;
|
|
|
|
fh.decreaseKey(node3, 5);
|
|
std::cout << fh << std::endl;
|
|
std::cout << "Top : " << *fh.top() << std::endl;
|
|
|
|
fh.pop();
|
|
std::cout << fh << std::endl;
|
|
std::cout << "Top : " << *fh.top() << std::endl;
|
|
|
|
fh.pop(); fh.pop();
|
|
std::cout << fh << std::endl;
|
|
|
|
delete node1;
|
|
delete node2;
|
|
delete node3;
|
|
} |