Commit d42b3acd authored by Ing. Jan Trávníček's avatar Ing. Jan Trávníček

redesign heaps to unify comparator interface

parent 0b7f3ab0
......@@ -13,67 +13,58 @@
namespace alib {
/// binomial heap used as mergeable priority queue
template < typename elem_t >
/// heap build using C++ algorithm features
template < typename T, typename Comparator = std::less < T > >
class CppHeap {
public:
CppHeap( int (* compare)( const elem_t &, const elem_t & ) );
~CppHeap();
CppHeap( Comparator comparator = Comparator ( ) ) : m_comparator( comparator ) {
}
/// inserts a node with new value into the heap
void insert( const elem_t & value );
// inserts a node with new value into the heap
void insert ( const T & value );
/// finds the maximum value in the heap
const elem_t & getMax() const {
return _data.front ( );
const T & getMax ( ) const {
return m_data.front ( );
}
/// finds and removes the maximum value from the heap
elem_t extractMax();
T extractMax ( );
/// merges this heap with another heap (!! this is a DESTRUCTIVE merge, heap in argument will be cleared !!)
void mergeWith( CppHeap<elem_t> && that );
void mergeWith ( CppHeap < T, Comparator > && that );
size_t size() const {
return _data.size ( );
size_t size ( ) const {
return m_data.size ( );
}
protected:
int (* _compare)( const elem_t &, const elem_t & ); ///< user-defined comparator function
std::vector < elem_t > _data;
Comparator m_comparator;
std::vector < T > m_data;
};
template< typename elem_t >
CppHeap<elem_t>::CppHeap( int (* compare)( const elem_t &, const elem_t & ) ) : _compare( compare ) {
}
template< typename elem_t >
CppHeap<elem_t>::~CppHeap() {
}
template< typename elem_t >
void CppHeap<elem_t>::insert( const elem_t & value ) {
_data.push_back ( value );
std::push_heap ( _data.begin ( ), _data.end ( ), _compare );
template < typename T, typename Comparator >
void CppHeap < T, Comparator >::insert ( const T & value ) {
m_data.push_back ( value );
std::push_heap ( m_data.begin ( ), m_data.end ( ), m_comparator );
}
template< typename elem_t >
elem_t CppHeap<elem_t>::extractMax() {
if ( _data.size ( ) == 0 )
template < typename T, typename Comparator >
T CppHeap < T, Comparator >::extractMax ( ) {
if ( m_data.size ( ) == 0 )
throw std::out_of_range ( "Heap is empty." );
elem_t res = _data.front ( );
std::pop_heap ( _data.begin ( ), _data.end ( ), _compare );
_data.pop_back ( );
std::pop_heap ( m_data.begin ( ), m_data.end ( ), m_comparator );
T res = std::move ( m_data.back ( ) );
m_data.pop_back ( );
return res;
}
template< typename elem_t >
void CppHeap<elem_t>::mergeWith( CppHeap<elem_t> && that ) {
_data.insert ( _data.end ( ), that._data.begin ( ), that._data.end ( ) );
std::make_heap ( _data.begin ( ), _data.end ( ), _compare );
template < typename T, typename Comparator >
void CppHeap < T, Comparator >::mergeWith( CppHeap < T, Comparator > && that ) {
m_data.insert ( m_data.end ( ), that.m_data.begin ( ), that.m_data.end ( ) );
std::make_heap ( m_data.begin ( ), m_data.end ( ), m_comparator );
}
} /* namespace alib */
......
/*
* FibonacciHeap.h
*
* Created on: Apr 7, 2016
* Author: Jan Broz
* Created on: Apr 7, 2016
* Author: Jan Broz
*/
#ifndef FIBONACCI_HEAP_INCLUDED
#define FIBONACCI_HEAP_INCLUDED
#include <stdexcept>
#include <cmath> // maxDegree
#include <cmath> // maxDegree
namespace alib {
/// fibonacci heap used as mergeable priority queue
template< typename elem_t >
// fibonacci heap used as mergeable priority queue
template < typename T, typename Comparator >
class FibonacciHeap {
int threeWay ( const T & a, const T & b ) const {
bool less = _compare ( a, b );
bool more = _compare ( b, a );
if ( ! less && ! more )
return 0;
else if ( less )
return -1;
else
return 1;
}
public:
FibonacciHeap( int (* compare)( const elem_t &, const elem_t & ) );
FibonacciHeap ( Comparator comparator = Comparator ( ) ) : _max( nullptr ), _size( 0 ), _compare( comparator ) {
}
~FibonacciHeap();
~FibonacciHeap ( );
/// inserts a node with new value into the heap
void insert( const elem_t & value );
// inserts a node with new value into the heap
void insert ( const T & value );
/// finds the maximum value in the heap
const elem_t & getMax() const {
// finds the maximum value in the heap
const T & getMax ( ) const {
return _max->value;
}
/// finds and removes the maximum value from the heap
elem_t extractMax();
// finds and removes the maximum value from the heap
T extractMax ( );
/// merges this heap with another heap (!! this is a DESTRUCTIVE merge, heap in argument will be cleared !!)
void mergeWith( FibonacciHeap<elem_t> && that );
// merges this heap with another heap (!! this is a DESTRUCTIVE merge, heap in argument will be cleared !!)
void mergeWith ( FibonacciHeap< T, Comparator > && that );
size_t size() const {
size_t size ( ) const {
return _size;
}
......@@ -45,33 +57,33 @@ public:
protected:
struct Node {
elem_t value;
T value;
unsigned degree;
bool mark;
bool mark;
Node * parent;
Node * child;
Node * prev;
Node * next;
Node(const elem_t & val, unsigned deg = 0, Node * par = nullptr, Node * chld = nullptr, Node * pr = nullptr, Node * ne = nullptr)
Node(const T & val, unsigned deg = 0, Node * par = nullptr, Node * chld = nullptr, Node * pr = nullptr, Node * ne = nullptr)
: value(val), degree(deg), mark(false), parent(par), child(chld), prev(pr), next(ne) {}
};
Node * _max; ///< pointer to cyclic doubly linked list of trees
size_t _size; ///< count of elements stored in the heap
int (* _compare)( const elem_t &, const elem_t & ); ///< user-defined comparator function
Node * _max; //< pointer to cyclic doubly linked list of trees
size_t _size; //< count of elements stored in the heap
Comparator _compare; //< user-defined comparator function
protected:
/// deletes one linked list of trees
// deletes one linked list of trees
void deleteTreeList( Node * head );
/// connects doubly linked lists from 2 fibonacci heaps and returns address of head of the new linked list
// connects doubly linked lists from 2 fibonacci heaps and returns address of head of the new linked list
void mergeHeaps( Node * & max1, Node * & max2 );
/// goes through list of trees and merges trees with same degree
// goes through list of trees and merges trees with same degree
void consolidate();
/// links tree to child list of node
// links tree to child list of node
void linkTreeToNode( Node * node, Node * tree );
// void printNode ( Node * node );
......@@ -80,17 +92,13 @@ protected:
};
template< typename elem_t >
FibonacciHeap<elem_t>::FibonacciHeap ( int (* compare)( const elem_t &, const elem_t & ) ) : _max( nullptr ), _size( 0 ), _compare( compare ) {
}
template< typename elem_t >
FibonacciHeap<elem_t>::~FibonacciHeap ( ) {
template < typename T, typename Comparator >
FibonacciHeap< T, Comparator >::~FibonacciHeap ( ) {
deleteTreeList( _max );
}
template< typename elem_t >
void FibonacciHeap<elem_t>::deleteTreeList( Node * head ) {
template < typename T, typename Comparator >
void FibonacciHeap< T, Comparator >::deleteTreeList( Node * head ) {
if ( ! head )
return;
......@@ -103,32 +111,32 @@ void FibonacciHeap<elem_t>::deleteTreeList( Node * head ) {
} while (actual != head);
}
template< typename elem_t >
void FibonacciHeap<elem_t>::insert( const elem_t & value ) {
template < typename T, typename Comparator >
void FibonacciHeap< T, Comparator >::insert( const T & value ) {
Node * newNode = new Node( value, 0, nullptr, nullptr, nullptr, nullptr );
newNode->prev = newNode;
newNode->next = newNode; // make this node be a single-element cyclic list
newNode->next = newNode; // make this node be a single-element cyclic list
if (!_max) {
_max = newNode; // this heap is empty, newNode becomes head of a linked list
_max = newNode; // this heap is empty, newNode becomes head of a linked list
_size = 1;
return;
}
mergeHeaps( _max, newNode ); // link the newNode into the existing linked list
mergeHeaps( _max, newNode ); // link the newNode into the existing linked list
_max = _compare( _max->value, newNode->value ) > 0 ? _max : newNode;
_max = threeWay ( _max->value, newNode->value ) > 0 ? _max : newNode;
_size++;
}
template< typename elem_t >
elem_t FibonacciHeap<elem_t>::extractMax() {
template < typename T, typename Comparator >
T FibonacciHeap< T, Comparator >::extractMax() {
if ( _max == nullptr )
throw std::out_of_range ( "Heap is empty." );
Node * z = _max;
elem_t maxVal = z->value;
T maxVal = z->value;
if (z->child != nullptr) {
Node * z1 = z->child;
......@@ -154,35 +162,35 @@ elem_t FibonacciHeap<elem_t>::extractMax() {
return maxVal;
}
template< typename elem_t >
void FibonacciHeap<elem_t>::mergeWith( FibonacciHeap<elem_t> && that ) {
if (this->_compare != that._compare) // nodes of these heaps are sorted by different condition
template < typename T, typename Comparator >
void FibonacciHeap< T, Comparator >::mergeWith( FibonacciHeap< T, Comparator > && that ) {
if (this->_compare != that._compare) // nodes of these heaps are sorted by different condition
throw std::logic_error("compare functions aren't equal, unable to merge");
mergeHeaps( this->_max, that._max ); // link the other heap into this heap
this->_max = _compare( _max->value, that._max->value ) > 0 ? this->_max : that._max;
mergeHeaps( this->_max, that._max ); // link the other heap into this heap
this->_max = threeWay ( _max->value, that._max->value ) > 0 ? this->_max : that._max;
that._max = nullptr;
this->_size += that._size;
that._size = 0;
}
template< typename elem_t >
void FibonacciHeap<elem_t>::mergeHeaps( Node * & max1, Node * & max2 ) {
template < typename T, typename Comparator >
void FibonacciHeap< T, Comparator >::mergeHeaps( Node * & max1, Node * & max2 ) {
if ( ! max1 ) {
max1 = max2; // this heap is empty, move the content from the other heap inside
max1 = max2; // this heap is empty, move the content from the other heap inside
} else if ( max2 ) {
Node * max2prev = max2->prev;
max2->prev->next = max1;
max2->prev = max1->prev; // this magicaly works even if the lists contain only one node
max2->prev = max1->prev; // this magicaly works even if the lists contain only one node
max1->prev->next = max2;
max1->prev = max2prev;
}
}
template< typename elem_t >
void FibonacciHeap<elem_t>::consolidate() {
template < typename T, typename Comparator >
void FibonacciHeap< T, Comparator >::consolidate() {
unsigned maxDegree = log2( _size );
Node * * rootsByDegree = new Node * [ maxDegree + 1 ];
for (unsigned i = 0; i <= maxDegree; i++)
......@@ -201,7 +209,7 @@ void FibonacciHeap<elem_t>::consolidate() {
Node * other = rootsByDegree[ actual->degree ];
rootsByDegree[ actual->degree ] = nullptr;
if (_compare( actual->value, other->value ) > 0) {
if ( threeWay ( actual->value, other->value ) > 0) {
linkTreeToNode( actual, other );
} else {
linkTreeToNode( other, actual );
......@@ -217,14 +225,14 @@ void FibonacciHeap<elem_t>::consolidate() {
_max = actual;
Node * node = actual;
do {
if (_compare( node->value, _max->value ) > 0)
if ( threeWay ( node->value, _max->value ) > 0)
_max = node;
node = node->next;
} while ( node != actual );
}
template< typename elem_t >
void FibonacciHeap<elem_t>::linkTreeToNode( Node * node, Node * tree ) {
template < typename T, typename Comparator >
void FibonacciHeap< T, Comparator >::linkTreeToNode( Node * node, Node * tree ) {
tree->prev->next = tree->next;
tree->next->prev = tree->prev;
......@@ -237,16 +245,16 @@ void FibonacciHeap<elem_t>::linkTreeToNode( Node * node, Node * tree ) {
mergeHeaps ( node->child, tree );
}
/*template < typename elem_t >
void FibonacciHeap<elem_t>::print() {
/*template < typename T, typename Comparator >
void FibonacciHeap< T, Comparator >::print() {
if ( _max == nullptr )
std::cout << "Empty" << std::endl;
printNode ( _max );
}
template < typename elem_t >
void FibonacciHeap < elem_t >::printNode ( Node * node ) {
template < typename T, typename Comparator >
void FibonacciHeap < T >::printNode ( Node * node ) {
if ( node == nullptr )
return;
......@@ -259,13 +267,13 @@ void FibonacciHeap < elem_t >::printNode ( Node * node ) {
} while ( node != actual );
}
template < typename elem_t >
void FibonacciHeap<elem_t>::checkConsystency() {
template < typename T, typename Comparator >
void FibonacciHeap< T, Comparator >::checkConsystency() {
checkConsystency ( _max, nullptr );
}
template < typename elem_t >
void FibonacciHeap < elem_t >::checkConsystency ( Node * node, Node * parent ) {
template < typename T, typename Comparator >
void FibonacciHeap < T >::checkConsystency ( Node * node, Node * parent ) {
if ( node == nullptr )
return;
......
......@@ -4,19 +4,15 @@
#include <alib/binomial_heap>
#include <alib/fibonacci_heap>
static int comparator ( const int & a, const int & b ) {
return ( b < a ) - ( a < b );
}
static int less ( const int & a, const int & b ) {
return a < b;
}
TEST_CASE ( "Heaps Test", "[unit][std][bits]" ) {
SECTION ( "Heaps" ) {
alib::BinomialHeap < int > bHeap ( comparator );
alib::CppHeap < int > cHeap ( less );
alib::FibonacciHeap < int > fHeap ( comparator );
alib::BinomialHeap < int, int ( * ) ( const int &, const int & ) > bHeap ( less );
alib::CppHeap < int, int ( * ) ( const int &, const int & ) > cHeap ( less );
alib::FibonacciHeap < int, int ( * ) ( const int &, const int & ) > fHeap ( less );
auto size = [ & ] ( ) {
int b = bHeap.size ( );
......@@ -46,9 +42,9 @@ TEST_CASE ( "Heaps Test", "[unit][std][bits]" ) {
};
auto mergeRandom = [ & ] ( unsigned limit ) {
alib::BinomialHeap < int > rbHeap ( comparator );
alib::CppHeap < int > rcHeap ( comparator );
alib::FibonacciHeap < int > rfHeap ( comparator );
alib::BinomialHeap < int, int ( * ) ( const int &, const int & ) > rbHeap ( less );
alib::CppHeap < int, int ( * ) ( const int &, const int & ) > rcHeap ( less );
alib::FibonacciHeap < int, int ( * ) ( const int &, const int & ) > rfHeap ( less );
for ( unsigned i = 0; i < limit; ++ i ) {
unsigned val = rand ( ) % 1000;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment