Adaptagrams
pairing_heap.h
1 /*
2  * vim: ts=4 sw=4 et tw=0 wm=0
3  *
4  * libvpsc - A solver for the problem of Variable Placement with
5  * Separation Constraints.
6  *
7  * Copyright (C) 2005 Mark Allen Weiss
8  * Copyright (C) 2005-2008 Monash University
9  *
10  * ----------------------------------------------------------------------------
11  * Pairing heap datastructure implementation:
12  * Based on example code in "Data structures and Algorithm Analysis in C++"
13  * by Mark Allen Weiss, used and released under the LGPL by permission
14  * of the author.
15  * No promises about correctness. Use at your own risk!
16  * ----------------------------------------------------------------------------
17  *
18  * This library is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU Lesser General Public
20  * License as published by the Free Software Foundation; either
21  * version 2.1 of the License, or (at your option) any later version.
22  * See the file LICENSE.LGPL distributed with the library.
23  *
24  * This library is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
27  *
28  * Author(s): Mark Allen Weiss
29  * Tim Dwyer
30 */
31 
32 #ifndef VPSC_PAIRING_HEAP_H
33 #define VPSC_PAIRING_HEAP_H
34 
35 #include <cstdlib>
36 #include <fstream>
37 #include <vector>
38 #include <list>
39 
40 #include "libvpsc/assertions.h"
41 
42 class Underflow { };
43 
44 // Pairing heap class
45 //
46 // CONSTRUCTION: with no parameters
47 //
48 // ******************PUBLIC OPERATIONS*********************
49 // PairNode & insert( x ) --> Insert x
50 // deleteMin( minItem ) --> Remove (and optionally return) smallest item
51 // T findMin( ) --> Return smallest item
52 // bool isEmpty( ) --> Return true if empty; else false
53 // void makeEmpty( ) --> Remove all items
54 // void decreaseKey( PairNode p, newVal )
55 // --> Decrease value in node p
56 // ******************ERRORS********************************
57 // Throws Underflow as warranted
58 
59 
60 template <class T>
61 struct PairNode
62 {
63  T element;
64  PairNode *leftChild;
65  PairNode *nextSibling;
66  PairNode *prev;
67 
68  PairNode( const T & theElement ) :
69  element( theElement ),
70  leftChild(nullptr), nextSibling(nullptr), prev(nullptr)
71  { }
72 };
73 
74 template <class T, class TCompare>
75 class PairingHeap;
76 
77 template <class T,class TCompare>
78 std::ostream& operator <<(std::ostream &os, const PairingHeap<T,TCompare> &b);
79 
80 template <class T, class TCompare = std::less<T> >
81 class PairingHeap
82 {
83 #ifndef SWIG
84  friend std::ostream& operator<< <T,TCompare> (std::ostream &os, const PairingHeap<T,TCompare> &b);
85 #endif
86 public:
87  PairingHeap() : root(nullptr), counter(0), siblingsTreeArray(5) { }
88  PairingHeap(const PairingHeap & rhs) {
89  // uses operator= to make deep copy
90  *this = rhs;
91  }
92  ~PairingHeap() { makeEmpty(); }
93  const PairingHeap & operator=( const PairingHeap & rhs );
94  bool isEmpty() const { return root == nullptr; }
95  unsigned size() const { return counter; }
96  PairNode<T> *insert( const T & x );
97  const T & findMin( ) const;
98  void deleteMin( );
99  const T extractMin( ) {
100  T v = findMin();
101  deleteMin();
102  return v;
103  }
104  void makeEmpty() {
105  reclaimMemory(root);
106  root = nullptr;
107  counter = 0;
108  }
109  void decreaseKey( PairNode<T> *p, const T & newVal );
110  void merge( PairingHeap<T,TCompare> *rhs );
111 protected:
112  // Destructively gets the root for merging into another heap.
113  PairNode<T> * removeRootForMerge(unsigned& size) {
114  PairNode<T> *r=root;
115  root=nullptr;
116  size=counter;
117  counter=0;
118  return r;
119  }
120  TCompare lessThan;
121 private:
122  PairNode<T> *root;
123  unsigned counter;
124 
125  // Used by PairingHeap::combineSiblings(). We keep this as member
126  // variable to save some vector resize operations during subsequent uses.
127  std::vector<PairNode<T> *> siblingsTreeArray;
128 
129  void reclaimMemory( PairNode<T> *t ) const;
130  void compareAndLink( PairNode<T> * & first, PairNode<T> *second ) const;
131  PairNode<T> * combineSiblings( PairNode<T> *firstSibling );
132  PairNode<T> * clone( PairNode<T> * t ) const;
133 };
134 
135 
140 template <class T,class TCompare>
141 PairNode<T> *
142 PairingHeap<T,TCompare>::insert( const T & x )
143 {
144  PairNode<T> *newNode = new PairNode<T>( x );
145 
146  if( root == nullptr )
147  root = newNode;
148  else
149  compareAndLink( root, newNode );
150  counter++;
151  return newNode;
152 }
153 
158 template <class T,class TCompare>
159 const T & PairingHeap<T,TCompare>::findMin( ) const
160 {
161  if( isEmpty( ) )
162  throw Underflow( );
163  return root->element;
164 }
169 template <class T,class TCompare>
170 void PairingHeap<T,TCompare>::deleteMin( )
171 {
172  if( isEmpty( ) )
173  throw Underflow( );
174 
175  PairNode<T> *oldRoot = root;
176 
177  if( root->leftChild == nullptr )
178  root = nullptr;
179  else
180  root = combineSiblings( root->leftChild );
181  COLA_ASSERT(counter);
182  counter--;
183  delete oldRoot;
184 }
185 
189 template <class T,class TCompare>
190 const PairingHeap<T,TCompare> &
191 PairingHeap<T,TCompare>::operator=( const PairingHeap<T,TCompare> & rhs )
192 {
193  if( this != &rhs )
194  {
195  makeEmpty( );
196  root = clone( rhs.root );
197  counter = rhs.size();
198  }
199 
200  return *this;
201 }
202 
207 template <class T,class TCompare>
208 void PairingHeap<T,TCompare>::reclaimMemory( PairNode<T> * t ) const
209 {
210  if( t != nullptr )
211  {
212  reclaimMemory( t->leftChild );
213  reclaimMemory( t->nextSibling );
214  delete t;
215  }
216 }
217 
225 template <class T,class TCompare>
226 void PairingHeap<T,TCompare>::decreaseKey( PairNode<T> *p,
227  const T & newVal )
228 {
229  COLA_ASSERT(!lessThan(p->element,newVal)); // newVal cannot be bigger
230  p->element = newVal;
231  if( p != root )
232  {
233  if( p->nextSibling != nullptr )
234  p->nextSibling->prev = p->prev;
235  if( p->prev->leftChild == p )
236  p->prev->leftChild = p->nextSibling;
237  else
238  p->prev->nextSibling = p->nextSibling;
239 
240  p->nextSibling = nullptr;
241  compareAndLink( root, p );
242  }
243 }
244 
248 template <class T,class TCompare>
249 void PairingHeap<T,TCompare>::merge( PairingHeap<T,TCompare> *rhs )
250 {
251  unsigned rhsSize;
252  PairNode<T> *broot=rhs->removeRootForMerge(rhsSize);
253  if (root == nullptr) {
254  root = broot;
255  } else {
256  compareAndLink(root, broot);
257  }
258  counter+=rhsSize;
259 }
260 
269 template <class T,class TCompare>
270 void PairingHeap<T,TCompare>::
271 compareAndLink( PairNode<T> * & first,
272  PairNode<T> *second ) const
273 {
274  if( second == nullptr )
275  return;
276 
277  if( lessThan(second->element,first->element) )
278  {
279  // Attach first as leftmost child of second
280  second->prev = first->prev;
281  first->prev = second;
282  first->nextSibling = second->leftChild;
283  if( first->nextSibling != nullptr )
284  first->nextSibling->prev = first;
285  second->leftChild = first;
286  first = second;
287  }
288  else
289  {
290  // Attach second as leftmost child of first
291  second->prev = first;
292  first->nextSibling = second->nextSibling;
293  if( first->nextSibling != nullptr )
294  first->nextSibling->prev = first;
295  second->nextSibling = first->leftChild;
296  if( second->nextSibling != nullptr )
297  second->nextSibling->prev = second;
298  first->leftChild = second;
299  }
300 }
301 
307 template <class T,class TCompare>
308 PairNode<T> *
309 PairingHeap<T,TCompare>::combineSiblings( PairNode<T> *firstSibling )
310 {
311  if( firstSibling->nextSibling == nullptr )
312  return firstSibling;
313 
314  // Store the subtrees in an array
315  int numSiblings = 0;
316  for( ; firstSibling != nullptr; numSiblings++ )
317  {
318  if( numSiblings == (int)siblingsTreeArray.size( ) )
319  siblingsTreeArray.resize( numSiblings * 2 );
320  siblingsTreeArray[ numSiblings ] = firstSibling;
321  firstSibling->prev->nextSibling = nullptr; // break links
322  firstSibling = firstSibling->nextSibling;
323  }
324  if( numSiblings == (int)siblingsTreeArray.size( ) )
325  siblingsTreeArray.resize( numSiblings + 1 );
326  siblingsTreeArray[ numSiblings ] = nullptr;
327 
328  // Combine subtrees two at a time, going left to right
329  int i = 0;
330  for( ; i + 1 < numSiblings; i += 2 )
331  compareAndLink( siblingsTreeArray[ i ], siblingsTreeArray[ i + 1 ] );
332 
333  int j = i - 2;
334 
335  // j has the result of last compareAndLink.
336  // If an odd number of trees, get the last one.
337  if( j == numSiblings - 3 )
338  compareAndLink( siblingsTreeArray[ j ], siblingsTreeArray[ j + 2 ] );
339 
340  // Now go right to left, merging last tree with
341  // next to last. The result becomes the new last.
342  for( ; j >= 2; j -= 2 )
343  compareAndLink( siblingsTreeArray[ j - 2 ], siblingsTreeArray[ j ] );
344  return siblingsTreeArray[ 0 ];
345 }
346 
351 template <class T,class TCompare>
352 PairNode<T> *
353 PairingHeap<T,TCompare>::clone( PairNode<T> * t ) const
354 {
355  if( t == nullptr )
356  return nullptr;
357  else
358  {
359  PairNode<T> *p = new PairNode<T>( t->element );
360  if( ( p->leftChild = clone( t->leftChild ) ) != nullptr )
361  p->leftChild->prev = p;
362  if( ( p->nextSibling = clone( t->nextSibling ) ) != nullptr )
363  p->nextSibling->prev = p;
364  return p;
365  }
366 }
367 
368 template <class T,class TCompare>
369 std::ostream& operator <<(std::ostream &os, const PairingHeap<T,TCompare> &b)
370 {
371  os<<"Heap:";
372  if (b.root != nullptr) {
373  PairNode<T> *r = b.root;
374  std::list<PairNode<T>*> q;
375  q.push_back(r);
376  while (!q.empty()) {
377  r = q.front();
378  q.pop_front();
379  if (r->leftChild != nullptr) {
380  os << *r->element << ">";
381  PairNode<T> *c = r->leftChild;
382  while (c != nullptr) {
383  q.push_back(c);
384  os << "," << *c->element;
385  c = c->nextSibling;
386  }
387  os << "|";
388  }
389  }
390  }
391  return os;
392 }
393 
394 #endif /* VPSC_PAIRING_HEAP_H */