/* * vim: ts=4 sw=4 et tw=0 wm=0 * * libvpsc - A solver for the problem of Variable Placement with * Separation Constraints. * * Copyright (C) 2005 Mark Allen Weiss * Copyright (C) 2005-2008 Monash University * * ---------------------------------------------------------------------------- * Pairing heap datastructure implementation: * Based on example code in "Data structures and Algorithm Analysis in C++" * by Mark Allen Weiss, used and released under the LGPL by permission * of the author. * No promises about correctness. Use at your own risk! * ---------------------------------------------------------------------------- * * 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 2.1 of the License, or (at your option) any later version. * See the file LICENSE.LGPL distributed with the library. * * 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. * * Author(s): Mark Allen Weiss * Tim Dwyer */ #ifndef VPSC_PAIRING_HEAP_H #define VPSC_PAIRING_HEAP_H #include #include #include #include #include "libvpsc/assertions.h" class Underflow { }; // Pairing heap class // // CONSTRUCTION: with no parameters // // ******************PUBLIC OPERATIONS********************* // PairNode & insert( x ) --> Insert x // deleteMin( minItem ) --> Remove (and optionally return) smallest item // T findMin( ) --> Return smallest item // bool isEmpty( ) --> Return true if empty; else false // void makeEmpty( ) --> Remove all items // void decreaseKey( PairNode p, newVal ) // --> Decrease value in node p // ******************ERRORS******************************** // Throws Underflow as warranted template struct PairNode { T element; PairNode *leftChild; PairNode *nextSibling; PairNode *prev; PairNode( const T & theElement ) : element( theElement ), leftChild(nullptr), nextSibling(nullptr), prev(nullptr) { } }; template class PairingHeap; template std::ostream& operator <<(std::ostream &os, const PairingHeap &b); template > class PairingHeap { #ifndef SWIG friend std::ostream& operator<< (std::ostream &os, const PairingHeap &b); #endif public: PairingHeap() : root(nullptr), counter(0), siblingsTreeArray(5) { } PairingHeap(const PairingHeap & rhs) { // uses operator= to make deep copy *this = rhs; } ~PairingHeap() { makeEmpty(); } const PairingHeap & operator=( const PairingHeap & rhs ); bool isEmpty() const { return root == nullptr; } unsigned size() const { return counter; } PairNode *insert( const T & x ); const T & findMin( ) const; void deleteMin( ); const T extractMin( ) { T v = findMin(); deleteMin(); return v; } void makeEmpty() { reclaimMemory(root); root = nullptr; counter = 0; } void decreaseKey( PairNode *p, const T & newVal ); void merge( PairingHeap *rhs ); protected: // Destructively gets the root for merging into another heap. PairNode * removeRootForMerge(unsigned& size) { PairNode *r=root; root=nullptr; size=counter; counter=0; return r; } TCompare lessThan; private: PairNode *root; unsigned counter; // Used by PairingHeap::combineSiblings(). We keep this as member // variable to save some vector resize operations during subsequent uses. std::vector *> siblingsTreeArray; void reclaimMemory( PairNode *t ) const; void compareAndLink( PairNode * & first, PairNode *second ) const; PairNode * combineSiblings( PairNode *firstSibling ); PairNode * clone( PairNode * t ) const; }; /** * Insert item x into the priority queue, maintaining heap order. * Return a pointer to the node containing the new item. */ template PairNode * PairingHeap::insert( const T & x ) { PairNode *newNode = new PairNode( x ); if( root == nullptr ) root = newNode; else compareAndLink( root, newNode ); counter++; return newNode; } /** * Find the smallest item in the priority queue. * Return the smallest item, or throw Underflow if empty. */ template const T & PairingHeap::findMin( ) const { if( isEmpty( ) ) throw Underflow( ); return root->element; } /** * Remove the smallest item from the priority queue. * Throws Underflow if empty. */ template void PairingHeap::deleteMin( ) { if( isEmpty( ) ) throw Underflow( ); PairNode *oldRoot = root; if( root->leftChild == nullptr ) root = nullptr; else root = combineSiblings( root->leftChild ); COLA_ASSERT(counter); counter--; delete oldRoot; } /** * Deep copy. */ template const PairingHeap & PairingHeap::operator=( const PairingHeap & rhs ) { if( this != &rhs ) { makeEmpty( ); root = clone( rhs.root ); counter = rhs.size(); } return *this; } /** * Internal method to make the tree empty. * WARNING: This is prone to running out of stack space. */ template void PairingHeap::reclaimMemory( PairNode * t ) const { if( t != nullptr ) { reclaimMemory( t->leftChild ); reclaimMemory( t->nextSibling ); delete t; } } /** * Change the value of the item stored in the pairing heap. * Does nothing if newVal is larger than currently stored value. * p points to a node returned by insert. * newVal is the new value, which must be smaller * than the currently stored value. */ template void PairingHeap::decreaseKey( PairNode *p, const T & newVal ) { COLA_ASSERT(!lessThan(p->element,newVal)); // newVal cannot be bigger p->element = newVal; if( p != root ) { if( p->nextSibling != nullptr ) p->nextSibling->prev = p->prev; if( p->prev->leftChild == p ) p->prev->leftChild = p->nextSibling; else p->prev->nextSibling = p->nextSibling; p->nextSibling = nullptr; compareAndLink( root, p ); } } /** * Merges rhs into this pairing heap by inserting its root */ template void PairingHeap::merge( PairingHeap *rhs ) { unsigned rhsSize; PairNode *broot=rhs->removeRootForMerge(rhsSize); if (root == nullptr) { root = broot; } else { compareAndLink(root, broot); } counter+=rhsSize; } /** * Internal method that is the basic operation to maintain order. * Links first and second together to satisfy heap order. * first is root of tree 1, which may not be nullptr. * first->nextSibling MUST be nullptr on entry. * second is root of tree 2, which may be nullptr. * first becomes the result of the tree merge. */ template void PairingHeap:: compareAndLink( PairNode * & first, PairNode *second ) const { if( second == nullptr ) return; if( lessThan(second->element,first->element) ) { // Attach first as leftmost child of second second->prev = first->prev; first->prev = second; first->nextSibling = second->leftChild; if( first->nextSibling != nullptr ) first->nextSibling->prev = first; second->leftChild = first; first = second; } else { // Attach second as leftmost child of first second->prev = first; first->nextSibling = second->nextSibling; if( first->nextSibling != nullptr ) first->nextSibling->prev = first; second->nextSibling = first->leftChild; if( second->nextSibling != nullptr ) second->nextSibling->prev = second; first->leftChild = second; } } /** * Internal method that implements two-pass merging. * firstSibling the root of the conglomerate; * assumed not nullptr. */ template PairNode * PairingHeap::combineSiblings( PairNode *firstSibling ) { if( firstSibling->nextSibling == nullptr ) return firstSibling; // Store the subtrees in an array int numSiblings = 0; for( ; firstSibling != nullptr; numSiblings++ ) { if( numSiblings == (int)siblingsTreeArray.size( ) ) siblingsTreeArray.resize( numSiblings * 2 ); siblingsTreeArray[ numSiblings ] = firstSibling; firstSibling->prev->nextSibling = nullptr; // break links firstSibling = firstSibling->nextSibling; } if( numSiblings == (int)siblingsTreeArray.size( ) ) siblingsTreeArray.resize( numSiblings + 1 ); siblingsTreeArray[ numSiblings ] = nullptr; // Combine subtrees two at a time, going left to right int i = 0; for( ; i + 1 < numSiblings; i += 2 ) compareAndLink( siblingsTreeArray[ i ], siblingsTreeArray[ i + 1 ] ); int j = i - 2; // j has the result of last compareAndLink. // If an odd number of trees, get the last one. if( j == numSiblings - 3 ) compareAndLink( siblingsTreeArray[ j ], siblingsTreeArray[ j + 2 ] ); // Now go right to left, merging last tree with // next to last. The result becomes the new last. for( ; j >= 2; j -= 2 ) compareAndLink( siblingsTreeArray[ j - 2 ], siblingsTreeArray[ j ] ); return siblingsTreeArray[ 0 ]; } /** * Internal method to clone subtree. * WARNING: This is prone to running out of stack space. */ template PairNode * PairingHeap::clone( PairNode * t ) const { if( t == nullptr ) return nullptr; else { PairNode *p = new PairNode( t->element ); if( ( p->leftChild = clone( t->leftChild ) ) != nullptr ) p->leftChild->prev = p; if( ( p->nextSibling = clone( t->nextSibling ) ) != nullptr ) p->nextSibling->prev = p; return p; } } template std::ostream& operator <<(std::ostream &os, const PairingHeap &b) { os<<"Heap:"; if (b.root != nullptr) { PairNode *r = b.root; std::list*> q; q.push_back(r); while (!q.empty()) { r = q.front(); q.pop_front(); if (r->leftChild != nullptr) { os << *r->element << ">"; PairNode *c = r->leftChild; while (c != nullptr) { q.push_back(c); os << "," << *c->element; c = c->nextSibling; } os << "|"; } } } return os; } #endif /* VPSC_PAIRING_HEAP_H */