/* PQ.h - implements pairing heaps priority queue (with multipass 'delete min') Copyright 2008 Vladimir Kolmogorov (vnk@ist.ac.at) This software can be used for research purposes only. Commercial use is prohibited. Public redistribution of the code or its derivatives is prohibited. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HFKSJHFKJHARBABDAKFAF #define HFKSJHFKJHARBABDAKFAF // exactly one flag must be defined //#define PQ_MULTIPASS #define PQ_INTERLEAVED_MULTIPASS #include template class PriorityQueue { public: struct Item { REAL slack; Item* parentPQ; union { struct { Item* leftPQ; Item* rightPQ; }; REAL y_saved; // used in repairs }; }; static void* AllocateBuf(); static void DeallocateBuf(void* buf); static void ResetItem(Item* i); static bool isReset(Item* i); ////////////////////////////////////////////////////////// void Reset(); void Add(Item* i); #define Remove(i, buf) _Remove(i) void _Remove(Item* i); void Decrease(Item* i_old, Item* i_new, void* buf); Item* GetMin(); ////////////////////////////////////////////////////////// void Update(REAL delta); void Merge(PriorityQueue& dest); // traversing items in the order they are stored (irrespective of slack). // The caller must go through all items, no other member functions can be called during the scan. Item* GetAndResetFirst(); Item* GetAndResetNext(); Item* GetFirst(); Item* GetNext(Item* i); ////////////////////////////////////////////////////////// private: struct Buf { }; Item* rootPQ; void RemoveRoot(); }; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// template inline void* PriorityQueue::AllocateBuf() { return NULL; } template inline void PriorityQueue::DeallocateBuf(void* _buf) { } template inline void PriorityQueue::ResetItem(Item* i) { i->parentPQ = NULL; } template inline bool PriorityQueue::isReset(Item* i) { return (i->parentPQ == NULL); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// template inline void PriorityQueue::Reset() { rootPQ = NULL; } /* template inline void PriorityQueue::RemoveRoot() { Item* r = rootPQ; PriorityQueue pq; pq.rootPQ = rootPQ; rootPQ = NULL; Item* i; for (i=pq.GetAndResetFirst(); i; i=pq.GetAndResetNext()) { if (i != r) Add(i); } r->parentPQ = NULL; } */ // sets i = merge(i, j). Ignores parentPQ and rightPQ for i and j. #define MERGE_PQ(i, j)\ {\ if (i->slack <= j->slack)\ {\ j->rightPQ = i->leftPQ;\ if (j->rightPQ) j->rightPQ->parentPQ = j;\ j->parentPQ = i;\ i->leftPQ = j;\ }\ else\ {\ i->rightPQ = j->leftPQ;\ if (i->rightPQ) i->rightPQ->parentPQ = i;\ i->parentPQ = j;\ j->leftPQ = i;\ i = j;\ }\ } template inline void PriorityQueue::RemoveRoot() { Item* i = rootPQ->leftPQ; rootPQ->parentPQ = NULL; if (i) { #ifdef PQ_MULTIPASS while ( i->rightPQ ) { Item** prev_ptr = &rootPQ; while ( 1 ) { if (i->rightPQ) { Item* j = i->rightPQ; Item* next = j->rightPQ; MERGE_PQ(i, j); *prev_ptr = i; if (!next) { i->rightPQ = NULL; break; } prev_ptr = &i->rightPQ; i = next; } else { *prev_ptr = i; i->rightPQ = NULL; break; } } i = rootPQ; } #endif #ifdef PQ_INTERLEAVED_MULTIPASS while ( i->rightPQ ) { Item* prev = NULL; while ( i ) { Item* next; if (i->rightPQ) { Item* j = i->rightPQ; next = j->rightPQ; MERGE_PQ(i, j); } else next = NULL; i->rightPQ = prev; prev = i; i = next; } i = prev; } #endif i->parentPQ = i; } rootPQ = i; } template inline void PriorityQueue::Add(Item* i) { if (!rootPQ) { rootPQ = i; i->parentPQ = i; i->leftPQ = i->rightPQ = NULL; } else if (i->slack <= rootPQ->slack) { rootPQ->parentPQ = i; i->leftPQ = rootPQ; i->rightPQ = NULL; rootPQ = i; i->parentPQ = i; } else { i->leftPQ = NULL; i->rightPQ = rootPQ->leftPQ; if (i->rightPQ) i->rightPQ->parentPQ = i; rootPQ->leftPQ = i; i->parentPQ = rootPQ; } } template inline void PriorityQueue::_Remove(Item* i) { Item* p = i->parentPQ; if (p == i) RemoveRoot(); else { if (i->rightPQ) i->rightPQ->parentPQ = p; if (p->leftPQ == i) p->leftPQ = i->rightPQ; else p->rightPQ = i->rightPQ; if (i->leftPQ) { i->parentPQ = i; i->rightPQ = NULL; PriorityQueue pq; pq.rootPQ = i; pq.RemoveRoot(); pq.Merge(*this); } else i->parentPQ = NULL; } } template inline void PriorityQueue::Decrease(Item* i_old, Item* i_new, void* _buf) { if (i_old->parentPQ == i_old) { if (i_old != i_new) { rootPQ = i_new; i_new->parentPQ = i_new; i_new->leftPQ = i_old->leftPQ; i_new->rightPQ = NULL; if (i_new->leftPQ) i_new->leftPQ->parentPQ = i_new; i_old->parentPQ = NULL; } } else { Remove(i_old, _buf); Add(i_new); } } template inline typename PriorityQueue::Item* PriorityQueue::GetMin() { return rootPQ; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// template inline void PriorityQueue::Merge(PriorityQueue& dest) { if (!rootPQ) return; if (!dest.rootPQ) dest.rootPQ = rootPQ; else { if (rootPQ->slack < dest.rootPQ->slack) { Item* j = rootPQ; rootPQ = dest.rootPQ; dest.rootPQ = j; } rootPQ->rightPQ = dest.rootPQ->leftPQ; if (rootPQ->rightPQ) rootPQ->rightPQ->parentPQ = rootPQ; rootPQ->parentPQ = dest.rootPQ; dest.rootPQ->leftPQ = rootPQ; } rootPQ = NULL; } template inline void PriorityQueue::Update(REAL delta) { if (!rootPQ) return; Item* i = rootPQ; while (i->leftPQ) i = i->leftPQ; while ( 1 ) { i->slack += delta; if (i->rightPQ) { i = i->rightPQ; while (i->leftPQ) i = i->leftPQ; } else { while ( 1 ) { Item* j = i; i = i->parentPQ; if (i == j) return; if (i->leftPQ == j) break; } } } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// template inline typename PriorityQueue::Item* PriorityQueue::GetAndResetFirst() { if (!rootPQ) return NULL; return GetAndResetNext(); } template inline typename PriorityQueue::Item* PriorityQueue::GetAndResetNext() { if (!rootPQ) return NULL; Item* result = rootPQ; result->parentPQ = NULL; Item* i = rootPQ->leftPQ; if (!i) rootPQ = result->rightPQ; else { rootPQ = i; while (i->rightPQ) i = i->rightPQ; i->rightPQ = result->rightPQ; } return result; } template inline typename PriorityQueue::Item* PriorityQueue::GetFirst() { if (!rootPQ) return NULL; Item* i = rootPQ; while (i->leftPQ) i = i->leftPQ; return i; } template inline typename PriorityQueue::Item* PriorityQueue::GetNext(Item* i) { if (i->rightPQ) { i = i->rightPQ; while (i->leftPQ) i = i->leftPQ; return i; } while ( 1 ) { Item* j = i; i = i->parentPQ; if (i == j) return NULL; if (i->leftPQ == j) return i; } } #endif