diff --git a/alib2std/src/alib/binomial_heap b/alib2std/src/alib/binomial_heap new file mode 100644 index 0000000000000000000000000000000000000000..beaad7c7411a655004584339c7465297e6a6d9de --- /dev/null +++ b/alib2std/src/alib/binomial_heap @@ -0,0 +1 @@ +#include <extensions/heaps/BinomialHeap.h> diff --git a/alib2std/src/alib/cpp_heap b/alib2std/src/alib/cpp_heap new file mode 100644 index 0000000000000000000000000000000000000000..bd542fa5d5a8b172df365c93199ed4e83f57a5c0 --- /dev/null +++ b/alib2std/src/alib/cpp_heap @@ -0,0 +1 @@ +#include <extensions/heaps/CppHeap.h> diff --git a/alib2std/src/alib/fibonacci_heap b/alib2std/src/alib/fibonacci_heap new file mode 100644 index 0000000000000000000000000000000000000000..08210d217a3849b3ff29a7e8483755d565fadf81 --- /dev/null +++ b/alib2std/src/alib/fibonacci_heap @@ -0,0 +1 @@ +#include <extensions/heaps/FibonacciHeap.h> diff --git a/alib2std/src/extensions/heaps/BinomialHeap.h b/alib2std/src/extensions/heaps/BinomialHeap.h new file mode 100644 index 0000000000000000000000000000000000000000..0f8ba284f32d87ef1759724b0b6e97f7f5a8246b --- /dev/null +++ b/alib2std/src/extensions/heaps/BinomialHeap.h @@ -0,0 +1,230 @@ +/* + * BinomialHeap.h + * + * Created on: Apr 7, 2016 + * Author: Jan Broz + */ + +#ifndef BINOMIAL_HEAP_INCLUDED +#define BINOMIAL_HEAP_INCLUDED + +#include <stdexcept> + +namespace alib { + +/// binomial heap used as mergeable priority queue +template< typename elem_t > +class BinomialHeap { +public: + + BinomialHeap( int (* compare)( const elem_t &, const elem_t & ) ); + + ~BinomialHeap(); + + /// inserts a node with new value into the heap + void insert( const elem_t & value ); + + /// finds the maximum value in the heap + const elem_t & getMax() const { + return (*searchMax( const_cast<Node**>(&_head) ))->value; + } + + /// finds and removes the maximum value from the heap + elem_t extractMax(); + + /// merges this heap with another heap (!! this is a DESTRUCTIVE merge, heap in argument will be cleared !!) + void mergeWith( BinomialHeap<elem_t> && that ); + + size_t size() const { + return _size; + } + +protected: + + struct Node { + elem_t value; + unsigned degree; + Node * parent; + Node * child; + Node * sibling; + Node( const elem_t & val, unsigned deg = 0, Node * par = NULL, Node * chld = NULL, Node * sib = NULL ) + : value(val), degree(deg), parent(par), child(chld), sibling(sib) {} + }; + + Node * _head; ///< head of a singly linked list of binomial trees + size_t _size; ///< count of elements stored in the heap + int (* _compare)( const elem_t &, const elem_t & ); ///< user-defined comparator function + +protected: + + /// deletes one linked list of binomial trees + void deleteTreeList( Node * head ); + + /// searches the linked list and returns address of variable pointing to the node with maximum value + Node * * searchMax( Node * * head ) const; + /// merges linked lists from 2 binomial heaps and returns address of head of the new linked list + + Node * mergeHeaps( Node * head1, Node * head2 ); + /// merges 2 linked lists of binomial trees and sorts the trees by increasing degree + + Node * mergeListsByDeg( Node * head1, Node * head2 ); + /// reverses a linked list + + Node * reverseList( Node * head ); + /// links root of tree1 to root of tree2 (tree1 becomes child of tree2) + Node * linkTreeToTree( Node * root1, Node * root2 ); + +}; + + +template< typename elem_t > +BinomialHeap<elem_t>::BinomialHeap( int (* compare)( const elem_t &, const elem_t & ) ) : _head( NULL ), _size( 0 ), _compare( compare ) { +} + +template< typename elem_t > +BinomialHeap<elem_t>::~BinomialHeap() { + deleteTreeList( _head ); +} + +template< typename elem_t > +void BinomialHeap<elem_t>::deleteTreeList( Node * head ) { + while (head != NULL) { + Node * sibling = head->sibling; + deleteTreeList( head->child ); + delete head; + head = sibling; + } +} + +template< typename elem_t > +void BinomialHeap<elem_t>::insert( const elem_t & value ) { + Node * newNode = new Node( value, 0, NULL, NULL, NULL ); + + _head = mergeHeaps( _head, newNode ); // merge the current heap with the newNode, + // as if the newNode was a single-element heap + _size++; +} + +template< typename elem_t > +elem_t BinomialHeap<elem_t>::extractMax() { + if ( _size == 0 ) + throw std::out_of_range ( "Heap is empty." ); + + Node * * ptrToMax = searchMax( &_head ); // find the node with maximum value + Node * max = *ptrToMax; + + *ptrToMax = max->sibling; // disconnect it from the linked list + + Node * chlHead = reverseList( max->child ); // merge them with the heap in reversed order + _head = mergeHeaps( this->_head, chlHead ); + + _size--; + elem_t maxVal = max->value; + delete max; // extract the value from node and return it + return maxVal; +} + +template< typename elem_t > +void BinomialHeap<elem_t>::mergeWith( BinomialHeap<elem_t> && 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"); + + this->_head = mergeHeaps( this->_head, that._head ); // move the other heap into this heap + that._head = NULL; + + this->_size += that._size; + that._size = 0; +} + +template< typename elem_t > +typename BinomialHeap<elem_t>::Node * * BinomialHeap<elem_t>::searchMax( Node * * head ) const { + Node * max = *head, * * ptrToMax = head; + for (Node * actual = * head, * prev = NULL; actual != NULL; prev = actual, actual = actual->sibling) { + if (_compare( actual->value, max->value ) > 0) { + max = actual; + ptrToMax = &prev->sibling; + } + } + return ptrToMax; +} + +template< typename elem_t > +typename BinomialHeap<elem_t>::Node * BinomialHeap<elem_t>::mergeHeaps( Node * head1, Node * head2 ) { + if ( ! head1 ) + return head2; + + if ( ! head2 ) + return head1; + + head1 = mergeListsByDeg( head1, head2 ); // first, merge the lists of trees by their degrees + + Node * actual = head1; + Node * * toLink = & head1; + while (actual->sibling) { + Node * next = actual->sibling; + + if (actual->degree != next->degree || (next->sibling && next->sibling->degree == actual->degree)) { + toLink = &actual->sibling; // not merging trees with same degree + actual = next; // or postponing the merge by 1 iteration + } else if (_compare( actual->value, next->value ) >= 0) { + actual->sibling = next->sibling; // merging 2 binomial trees with same degree + actual = linkTreeToTree( next, actual ); // 'next' becomes child of 'actual' + } else { + *toLink = next; // merging 2 binomial trees with same degree + actual = linkTreeToTree( actual, next ); // 'actual' becomes child of 'next' + } + } + + return head1; +} + +template< typename elem_t > +typename BinomialHeap<elem_t>::Node * BinomialHeap<elem_t>::mergeListsByDeg( Node * head1, Node * head2 ) { + Node * newHead = NULL; + Node * * toLink = &newHead; + while (head1 && head2) { + if (head1->degree < head2->degree) { + *toLink = head1; // linking node from first list + toLink = &head1->sibling; // and moving first pointer + head1 = head1->sibling; + } else { + *toLink = head2; // linking node from second list + toLink = &head2->sibling; // and moving second pointer + head2 = head2->sibling; + } + } + if (!head1) + *toLink = head2; // list1 ended, link the rest of list2 + else + *toLink = head1; // list2 ended, link the rest of list1 + + return newHead; +} + +template< typename elem_t > +typename BinomialHeap<elem_t>::Node * BinomialHeap<elem_t>::reverseList( Node * head ) { + Node * prev = NULL; + + while (head) { + Node * next = head->sibling; + head->sibling = prev; + prev = head; + head = next; + } + + return prev; +} + +template< typename elem_t > +typename BinomialHeap<elem_t>::Node * BinomialHeap<elem_t>::linkTreeToTree( Node * root1, Node * root2 ) { + root1->parent = root2; + root1->sibling = root2->child; + root2->child = root1; + root2->degree++; + + return root2; +} + +} /* namespace alib */ + +#endif // BINOMIAL_HEAP_INCLUDED diff --git a/alib2std/src/extensions/heaps/CppHeap.h b/alib2std/src/extensions/heaps/CppHeap.h new file mode 100644 index 0000000000000000000000000000000000000000..eeebc4a6f49a43697f649081353848d39e1b0aff --- /dev/null +++ b/alib2std/src/extensions/heaps/CppHeap.h @@ -0,0 +1,81 @@ +/* + * CppHeap.h + * + * Created on: Jan 9, 2019 + * Author: Jan Travnicek + */ + +#ifndef CPP_HEAP_INCLUDED +#define CPP_HEAP_INCLUDED + +#include <algorithm> +#include <vector> + +namespace alib { + +/// binomial heap used as mergeable priority queue +template < typename elem_t > +class CppHeap { +public: + CppHeap( int (* compare)( const elem_t &, const elem_t & ) ); + + ~CppHeap(); + + /// inserts a node with new value into the heap + void insert( const elem_t & value ); + + /// finds the maximum value in the heap + const elem_t & getMax() const { + return _data.front ( ); + } + + /// finds and removes the maximum value from the heap + elem_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 ); + + size_t size() const { + return _data.size ( ); + } + +protected: + int (* _compare)( const elem_t &, const elem_t & ); ///< user-defined comparator function + std::vector < elem_t > _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 elem_t > +elem_t CppHeap<elem_t>::extractMax() { + if ( _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 ( ); + 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 ); +} + +} /* namespace alib */ + +#endif // CPP_HEAP_INCLUDED diff --git a/alib2std/src/extensions/heaps/FibonacciHeap.h b/alib2std/src/extensions/heaps/FibonacciHeap.h new file mode 100644 index 0000000000000000000000000000000000000000..ec22399f757a3f194ef3d23981918c4c455518ab --- /dev/null +++ b/alib2std/src/extensions/heaps/FibonacciHeap.h @@ -0,0 +1,283 @@ +/* + * FibonacciHeap.h + * + * Created on: Apr 7, 2016 + * Author: Jan Broz + */ + +#ifndef FIBONACCI_HEAP_INCLUDED +#define FIBONACCI_HEAP_INCLUDED + +#include <stdexcept> +#include <cmath> // maxDegree + +namespace alib { + +/// fibonacci heap used as mergeable priority queue +template< typename elem_t > +class FibonacciHeap { +public: + FibonacciHeap( int (* compare)( const elem_t &, const elem_t & ) ); + + ~FibonacciHeap(); + + /// inserts a node with new value into the heap + void insert( const elem_t & value ); + + /// finds the maximum value in the heap + const elem_t & getMax() const { + return _max->value; + } + + /// finds and removes the maximum value from the heap + elem_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 ); + + size_t size() const { + return _size; + } + +// void print ( ); + +// void checkConsystency ( ); + +protected: + struct Node { + elem_t value; + unsigned degree; + bool mark; + Node * parent; + Node * child; + Node * prev; + Node * next; + Node(const elem_t & val, unsigned deg = 0, Node * par = NULL, Node * chld = NULL, Node * pr = NULL, Node * ne = NULL) + : 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 + +protected: + + /// 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 + void mergeHeaps( Node * & max1, Node * & max2 ); + + /// goes through list of trees and merges trees with same degree + void consolidate(); + + /// links tree to child list of node + void linkTreeToNode( Node * node, Node * tree ); + +// void printNode ( Node * node ); + +// void checkConsystency ( Node * node, Node * parent ); +}; + + +template< typename elem_t > +FibonacciHeap<elem_t>::FibonacciHeap ( int (* compare)( const elem_t &, const elem_t & ) ) : _max( NULL ), _size( 0 ), _compare( compare ) { +} + +template< typename elem_t > +FibonacciHeap<elem_t>::~FibonacciHeap ( ) { + deleteTreeList( _max ); +} + +template< typename elem_t > +void FibonacciHeap<elem_t>::deleteTreeList( Node * head ) { + if ( ! head ) + return; + + Node * actual = head; + do { + Node * next = actual->next; + deleteTreeList( actual->child ); + delete actual; + actual = next; + } while (actual != head); +} + +template< typename elem_t > +void FibonacciHeap<elem_t>::insert( const elem_t & value ) { + Node * newNode = new Node( value, 0, NULL, NULL, NULL, NULL ); + newNode->prev = newNode; + 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 + _size = 1; + return; + } + + mergeHeaps( _max, newNode ); // link the newNode into the existing linked list + + _max = _compare( _max->value, newNode->value ) > 0 ? _max : newNode; + + _size++; +} + +template< typename elem_t > +elem_t FibonacciHeap<elem_t>::extractMax() { + if ( _max == NULL ) + throw std::out_of_range ( "Heap is empty." ); + + Node * z = _max; + elem_t maxVal = z->value; + + if (z->child != NULL) { + Node * z1 = z->child; + do { + z1->parent = NULL; + z1 = z1->next; + } while (z1 != z->child); + } + + mergeHeaps ( z, z->child ); + + if (z == z->next) + _max = NULL; + else { + _max = z->next; + _max->prev = z->prev; + z->prev->next = _max; + consolidate(); + } + + _size--; + delete z; + 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 + 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; + that._max = NULL; + + this->_size += that._size; + that._size = 0; +} + +template< typename elem_t > +void FibonacciHeap<elem_t>::mergeHeaps( Node * & max1, Node * & max2 ) { + if ( ! max1 ) { + 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 + max1->prev->next = max2; + max1->prev = max2prev; + } +} + +template< typename elem_t > +void FibonacciHeap<elem_t>::consolidate() { + unsigned maxDegree = log2( _size ); + Node * * rootsByDegree = new Node * [ maxDegree + 1 ]; + for (unsigned i = 0; i <= maxDegree; i++) + rootsByDegree[i] = NULL; + + Node * next = _max; + Node * actual = next; + + bool finish = next == next->next; + while ( ! finish ) { + actual = next; + next = actual->next; + finish = next == rootsByDegree [ next->degree ]; + + while ( rootsByDegree[ actual->degree ] != NULL) { + Node * other = rootsByDegree[ actual->degree ]; + rootsByDegree[ actual->degree ] = NULL; + + if (_compare( actual->value, other->value ) > 0) { + linkTreeToNode( actual, other ); + } else { + linkTreeToNode( other, actual ); + actual = other; + } + + } + rootsByDegree[ actual->degree ] = actual; + }; + + delete [] rootsByDegree; + + _max = actual; + Node * node = actual; + do { + if (_compare( 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 ) { + tree->prev->next = tree->next; + tree->next->prev = tree->prev; + + tree->prev = tree; + tree->next = tree; + + tree->parent = node; + node->degree ++; + + mergeHeaps ( node->child, tree ); +} + +/*template < typename elem_t > +void FibonacciHeap<elem_t>::print() { + if ( _max == NULL ) + std::cout << "Empty" << std::endl; + + printNode ( _max ); +} + +template < typename elem_t > +void FibonacciHeap < elem_t >::printNode ( Node * node ) { + if ( node == NULL ) + return; + + Node * actual = node; + do { + std::cout << " Value: " << actual->value << " Parent: " << ((actual->parent) ? actual->parent->id : -1) << " Left: " << actual->prev->id << " Right: " << actual->next->id << std::endl; + printNode ( actual->child ); + actual = actual->next; + + } while ( node != actual ); +} + +template < typename elem_t > +void FibonacciHeap<elem_t>::checkConsystency() { + checkConsystency ( _max, NULL ); +} + +template < typename elem_t > +void FibonacciHeap < elem_t >::checkConsystency ( Node * node, Node * parent ) { + if ( node == NULL ) + return; + + Node * actual = node; + do { + assert ( node == node->prev->next && node->next->prev == node && node->parent == parent ); + checkConsystency ( actual->child, actual ); + actual = actual->next; + + } while ( node != actual ); +}*/ + +} /* namespace alib */ + +#endif // FIBONACCI_HEAP_INCLUDED diff --git a/alib2std/test-src/extensions/heaps/HeapsTest.cpp b/alib2std/test-src/extensions/heaps/HeapsTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53a6df9164f28d817a63631fac6d690af85a874b --- /dev/null +++ b/alib2std/test-src/extensions/heaps/HeapsTest.cpp @@ -0,0 +1,116 @@ +#include "HeapsTest.h" + +#include <alib/cpp_heap> +#include <alib/binomial_heap> +#include <alib/fibonacci_heap> + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( HeapsTest, "bits" ); +CPPUNIT_TEST_SUITE_REGISTRATION( HeapsTest ); + +void HeapsTest::setUp() { +} + +void HeapsTest::tearDown() { +} + +int comparator ( const int & a, const int & b ) { + return ( b < a ) - ( a < b ); +} + +int less ( const int & a, const int & b ) { + return a < b; +} + +void HeapsTest::testHeaps ( ) { + alib::BinomialHeap < int > bHeap ( comparator ); + alib::CppHeap < int > cHeap ( less ); + alib::FibonacciHeap < int > fHeap ( comparator ); + + auto size = [ & ] ( ) { + int b = bHeap.size ( ); + int c = cHeap.size ( ); + int f = fHeap.size ( ); + CPPUNIT_ASSERT ( b == c && c == f ); + return b; + }; + + auto push = [ & ] ( int a ) { + bHeap.insert ( a ); + cHeap.insert ( a ); + fHeap.insert ( a ); + }; + + auto pop = [ & ] ( ) { + int b = bHeap.extractMax ( ); + int c = cHeap.extractMax ( ); + int f = fHeap.extractMax ( ); + if ( b != c || c != f) { + std::cerr << "??" << std::endl << "size = " << size ( ) << std::endl; + std::cerr << "b = " << b << " c = " << c << " f = " << f << std::endl; + } + CPPUNIT_ASSERT ( b == c ); + CPPUNIT_ASSERT ( c == f ); + return b; + }; + + auto mergeRandom = [ & ] ( unsigned limit ) { + alib::BinomialHeap < int > rbHeap ( comparator ); + alib::CppHeap < int > rcHeap ( comparator ); + alib::FibonacciHeap < int > rfHeap ( comparator ); + + for ( unsigned i = 0; i < limit; ++ i ) { + unsigned val = rand ( ) % 1000; + rbHeap.insert ( val ); + rcHeap.insert ( val ); + rfHeap.insert ( val ); + } + + bHeap.mergeWith ( std::move ( rbHeap ) ); + cHeap.mergeWith ( std::move ( rcHeap ) ); + fHeap.mergeWith ( std::move ( rfHeap ) ); + }; + + push ( 1 ); + CPPUNIT_ASSERT ( size ( ) == 1 ); + CPPUNIT_ASSERT ( pop ( ) == 1 ); + std::cout << "merge random 50" << std::endl; + mergeRandom ( 50 ); + CPPUNIT_ASSERT ( size ( ) == 50 ); + std::cout << "pop 25" << std::endl; + for ( unsigned i = 0; i < 25; ++ i ) { + std::cout << "pop = " << pop ( ) << std::endl; + } + std::cout << "merge random 50" << std::endl; + mergeRandom ( 50 ); + CPPUNIT_ASSERT ( size ( ) == 75 ); + std::cout << "pop 25" << std::endl; + for ( unsigned i = 0; i < 25; ++ i ) { + std::cout << "pop = " << pop ( ) << std::endl; + } + std::cout << "merge random 50" << std::endl; + mergeRandom ( 50 ); + CPPUNIT_ASSERT ( size ( ) == 100 ); + std::cout << "pop 25" << std::endl; + for ( unsigned i = 0; i < 25; ++ i ) { + std::cout << "pop = " << pop ( ) << std::endl; + } + std::cout << "merge random 50" << std::endl; + mergeRandom ( 50 ); + CPPUNIT_ASSERT ( size ( ) == 125 ); + std::cout << "pop 25" << std::endl; + for ( unsigned i = 0; i < 25; ++ i ) { + std::cout << "pop = " << pop ( ) << std::endl; + } + std::cout << "merge random 50" << std::endl; + mergeRandom ( 50 ); + CPPUNIT_ASSERT ( size ( ) == 150 ); + std::cout << "push random 25" << std::endl; +// fHeap.checkConsystency ( ); + for ( unsigned i = 0; i < 25; ++ i ) { + push ( rand ( ) % 1000 ); + } + std::cout << "pop all" << std::endl; + for ( unsigned i = 0; i < 175; ++ i ) { + std::cout << "pop = " << pop ( ) << std::endl; + } +} diff --git a/alib2std/test-src/extensions/heaps/HeapsTest.h b/alib2std/test-src/extensions/heaps/HeapsTest.h new file mode 100644 index 0000000000000000000000000000000000000000..96a5efaed46582951de1be4ad02f110e94caba90 --- /dev/null +++ b/alib2std/test-src/extensions/heaps/HeapsTest.h @@ -0,0 +1,19 @@ +#ifndef HEAPS_TEST_H_ +#define HEAPS_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class HeapsTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( HeapsTest ); + CPPUNIT_TEST( testHeaps ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testHeaps(); +}; + +#endif // HEAPS_TEST_H_