w_heap.h

00001 /*<std-header orig-src='shore' incl-file-exclusion='W_HEAP_H'>
00002 
00003  $Id: w_heap.h,v 1.13 2010/05/26 01:20:25 nhall Exp $
00004 
00005 SHORE -- Scalable Heterogeneous Object REpository
00006 
00007 Copyright (c) 1994-99 Computer Sciences Department, University of
00008                       Wisconsin -- Madison
00009 All Rights Reserved.
00010 
00011 Permission to use, copy, modify and distribute this software and its
00012 documentation is hereby granted, provided that both the copyright
00013 notice and this permission notice appear in all copies of the
00014 software, derivative works or modified versions, and any portions
00015 thereof, and that both notices appear in supporting documentation.
00016 
00017 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00018 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00019 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00020 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00021 
00022 This software was developed with support by the Advanced Research
00023 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00024 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00025 Further funding for this work was provided by DARPA through
00026 Rome Research Laboratory Contract No. F30602-97-2-0247.
00027 
00028 */
00029 
00030 #ifndef W_HEAP_H
00031 #define W_HEAP_H
00032 
00033 #include "w_defines.h"
00034 
00035 /*  -- do not edit anything above this line --   </std-header>*/
00036 
00037 #include "w_base.h"
00038 
00039 
00040 /**\brief General-purpose heap.
00041  *
00042  * This class implements a general purpose heap.  
00043  * The element type T and the ordering function (via class Cmp)
00044  * are passed in as parameters to the Heap template.
00045  *
00046  * This heap sifts the LARGEST elements to the top and the
00047  * SMALLEST elements to the bottom, according tho the comparison
00048  * function, Cmp.gt().  Thus the "heap property" is that
00049  * value(Parent(i)) gt value(i) for each element i in the heap.
00050  *
00051  * An element anywhere in the heap can be changed (by an outsider-
00052  * not by the heap template) and the heap property can be restored,
00053  * but he who changes the element must know whether the element's
00054  * key value increased or decreased.  Since we're sifting "large"
00055  * elements to the top of the heap, if the element's key value increases,
00056  * the element must be sifted UP, and if its value decreases, it must
00057  * be sifted down.  The methods IncreaseN and DecreaseN
00058  * handle these cases.
00059  *
00060  * The heap has the following worst case run times:
00061  *
00062  *   - create initial heap        O(n)
00063  *   - retrieve first element     O(1)
00064  *   - retrieve second element    O(1)
00065  *   - replace first element      O(log n)
00066  *   - delete first element       O(log n)
00067  *   - add new element            O(log n)
00068  *   - increment/decrement key for any element O(log n)
00069  *
00070  * The comparison class, Cmp, must have the member functions
00071  *   gt (T* left, T* right) returns true iff left > right
00072  *
00073  * RemoveFirst always removes the largest element. 
00074  *
00075  ****************************************************************************/
00076 
00077 
00078 template <class T, class Cmp>
00079 class Heap
00080 {
00081     public:
00082                         Heap(const Cmp& cmpFunction, 
00083                                 int initialNumElements = 32);
00084                         ~Heap();
00085 
00086                         /**\brief How many elements in the heap? */
00087         int             NumElements() const; 
00088 
00089                         /**\brief Take top/largest element off */
00090         T               RemoveFirst();             
00091 
00092                         /**\brief Remove element from the middle */
00093         T               RemoveN(int i);      
00094 
00095                         /**\brief Put in heap and recompute to restore heap property */
00096         void            AddElement(const T& elem); 
00097 
00098                         /**\brief Put in heap but do NOT recompute to restore heap property */
00099         void            AddElementDontHeapify(const T& elem); 
00100                         /**\brief Recompute to restore heap property */
00101         void            Heapify(); 
00102 
00103                         /**\brief Get reference to top of heap (do not remove) */
00104         T&              First();
00105 
00106                         /**\brief Get reference arbitrary element (do not remove) */
00107         T&              Value(int i);       
00108 
00109                         /**\brief Get reference element just below top (do not remove) */
00110         const T&        Second() const;
00111 
00112                         /**\brief Inform heap that I replaced the top: recompute, but
00113                          * more efficient than Heapify() */
00114         void            ReplacedFirst();
00115 
00116                         /**\brief Inform heap that element \e i must rise in heap
00117                          * to restore heap property. More efficient than general 
00118                          * Heapify() */
00119         void            IncreasedN(int i); 
00120 
00121                         /**\brief Inform heap that element \e i must drop in heap
00122                          * to restore heap property. More efficient than general 
00123                          * Heapify() */
00124         void            DecreasedN(int i);
00125 
00126                         /**\brief Check heap property */
00127         void            CheckHeap() const; 
00128 
00129                         /**\brief Dump heap */
00130         void            Print(ostream& out) const;
00131 
00132                         /**\brief Check heap property from given
00133                          * root to the bottom */
00134         bool            HeapProperty(int root) const; 
00135 
00136     protected:
00137         int                numElements;
00138         int                maxNumElements;
00139         T*                 elements;
00140         const Cmp&         cmp;
00141 
00142         int                LeftChild(int i) const;
00143         int                RightChild(int i) const;
00144         int                RightSibling(int i) const;
00145         int                Parent(int i) const;
00146 
00147         void                PrintRoot(ostream& out, int rootElem, int indentLevel) const;
00148         void                CheckHeapRoot(int rootElem) const; 
00149                                 // check heap property for entire heap
00150         bool                HeapProperty(int lower, int upper) const; // check
00151                                 // heap property from lower->upper, inclusive
00152 
00153         void                SiftDown(int rootElem); // fix heap from rootElem
00154                                 // down to bottom of heap
00155         void                SiftUp(int rootElem); // fix heap from rootElem
00156                                 // to top of heap
00157 
00158         void                GrowElements(int newSize); // accommodate more 
00159 };
00160 
00161 
00162 // Mappings between children and parent array indices
00163 
00164 template<class T, class Cmp>
00165 inline int Heap<T, Cmp>::LeftChild(int i) const
00166 {
00167     return 2 * i + 1;
00168 }
00169 
00170 
00171 template<class T, class Cmp>
00172 inline int Heap<T, Cmp>::RightChild(int i) const
00173 {
00174     return 2 * i + 2;
00175 }
00176 
00177 
00178 template<class T, class Cmp>
00179 inline int Heap<T, Cmp>::RightSibling(int i) const
00180 {
00181     return i + 1;
00182 }
00183 
00184 
00185 template<class T, class Cmp>
00186 inline int Heap<T, Cmp>::Parent(int i) const
00187 {
00188     return (i - 1) / 2;
00189 }
00190 
00191 
00192 // short inlined functions
00193 
00194 template<class T, class Cmp>
00195 inline void Heap<T, Cmp>::CheckHeap() const
00196 {
00197     w_assert9(HeapProperty(0));
00198 }
00199 
00200 
00201 template<class T, class Cmp>
00202 inline int Heap<T, Cmp>::NumElements() const
00203 {
00204     return numElements;
00205 }
00206 
00207 
00208 template<class T, class Cmp>
00209 inline void Heap<T, Cmp>::Print(ostream& out) const
00210 {
00211     PrintRoot(out, 0, 0);
00212 }
00213 
00214 
00215 template<class T, class Cmp>
00216 inline void Heap<T, Cmp>::ReplacedFirst()
00217 {
00218     SiftDown(0);
00219 }
00220 
00221 template<class T, class Cmp>
00222 inline void Heap<T, Cmp>::IncreasedN(int n)
00223 {
00224     SiftUp(n);
00225 }
00226 
00227 template<class T, class Cmp>
00228 inline void Heap<T, Cmp>::DecreasedN(int n)
00229 {
00230     SiftDown(n);
00231 }
00232 
00233 
00234 template<class T, class Cmp>
00235 Heap<T, Cmp>::Heap(const Cmp& cmpFunction, int initialNumElements)
00236 :
00237     numElements(0),
00238     maxNumElements(initialNumElements),
00239     elements(0),
00240     cmp(cmpFunction)
00241 {
00242     elements = new T[initialNumElements];
00243 }
00244 
00245 
00246 template<class T, class Cmp>
00247 Heap<T, Cmp>::~Heap()
00248 {
00249     delete[] elements;
00250 }
00251 
00252 
00253 // removes and returns the first element.  maintains heap property.
00254 // runs in O(log n).
00255 template<class T, class Cmp>
00256 T Heap<T, Cmp>::RemoveN(int i)
00257 {
00258     w_assert9(numElements > 0);
00259     T temp = elements[i];
00260     bool smaller = cmp.gt(elements[i], elements[--numElements]);
00261     elements[i] = elements[numElements];
00262     if(smaller) {
00263         SiftDown(i);
00264     } else {
00265         SiftUp(i);
00266     }
00267     return temp;
00268 }
00269 
00270 template<class T, class Cmp>
00271 T Heap<T, Cmp>::RemoveFirst()
00272 {
00273     // return RemoveN(0);
00274     // This is pretty inefficient in comparisons if only
00275     // because we know that when removing the top element,
00276     // we're removing the largest one. So we include
00277     // an optimized version of RemoveN(i)
00278     T temp = elements[0];
00279     elements[0] = elements[--numElements];
00280     SiftDown(0);
00281     return temp;
00282 }
00283 
00284 
00285 // returns the First element in the heap.
00286 // runs in O(1).
00287 
00288 template<class T, class Cmp>
00289 T& Heap<T, Cmp>::First()
00290 {
00291     w_assert9(numElements > 0);
00292     return elements[0];
00293 }
00294 
00295 template<class T, class Cmp>
00296 T& Heap<T, Cmp>::Value(int i)
00297 {
00298     w_assert9(i < numElements && i >= 0);
00299     return elements[i];
00300 }
00301 
00302 // return the element which would become First if RemoveFirst() were called.
00303 // runs in O(1)
00304 
00305 template<class T, class Cmp>
00306 const T& Heap<T, Cmp>::Second() const
00307 {
00308     w_assert9(numElements > 1);
00309     int second = LeftChild(0);
00310     if (RightSibling(second) < numElements)  {
00311         if (cmp.gt(elements[RightSibling(second)], elements[second]))  {
00312             second = RightSibling(second);
00313         }
00314     }
00315     return elements[second];
00316 }
00317 
00318 
00319 // adds a new element to the heap, maintaining the heap property.
00320 // runs in O(log n)
00321 
00322 template<class T, class Cmp>
00323 void Heap<T, Cmp>::AddElement(const T& elem)
00324 {
00325     if (numElements >= maxNumElements)  {
00326         GrowElements(2 * maxNumElements);
00327     }
00328 
00329     int rootElem = numElements++; // get a new slot
00330     while (rootElem > 0)  {
00331         if (cmp.gt(elem, elements[Parent(rootElem)]))  {
00332             elements[rootElem] = elements[Parent(rootElem)];
00333             rootElem = Parent(rootElem);
00334         } else {
00335             break;
00336         }
00337     }
00338     elements[rootElem] = elem;
00339 }
00340             
00341 
00342 // use this to fill the heap initially.
00343 // proceed with a call to Heapify() when all elements are added.
00344 
00345 template<class T, class Cmp>
00346 void Heap<T, Cmp>::AddElementDontHeapify(const T& elem)
00347 {
00348     if (numElements >= maxNumElements)  {
00349         GrowElements(2 * maxNumElements);
00350     }
00351     elements[numElements++] = elem;
00352 }
00353 
00354 
00355 // recreates the heap condition.
00356 //
00357 // assumes the subtrees of rootElem are heaps and that
00358 // only rootElem violates the heap condition.
00359 //
00360 // starts at the rootElem and stops if there is a valid heap.
00361 // otherwise it sifts the rootElem down into the tree of the 
00362 // larger of the children.
00363 //
00364 // this runs in O(log n).
00365 
00366 template<class T, class Cmp>
00367 void Heap<T, Cmp>::SiftDown(int rootElem)
00368 {
00369     /*
00370      * Assumes: both children are legitimate heaps
00371      */
00372     if(LeftChild(rootElem) < numElements) {
00373         w_assert9(HeapProperty(LeftChild(rootElem)));
00374     }
00375     
00376     if (numElements > 1)  {
00377         const T rootValue = elements[rootElem];
00378         while (rootElem <= Parent(numElements - 1)) {
00379             w_assert9(LeftChild(rootElem) < numElements);
00380 
00381             // find sibling with larger value
00382             // Tends to sift down the larger side
00383             int child = LeftChild(rootElem);
00384             if (RightSibling(child) < numElements)  {
00385                 if (cmp.gt(elements[RightSibling(child)], elements[child]))  {
00386                     child = RightSibling(child);
00387                 }
00388             }
00389 
00390             // If the larger child is larger than the root, swap the root
00391             // with the larger child.  
00392             if (cmp.gt(elements[child], rootValue))  {
00393                 elements[rootElem] = elements[child];                // need to swap
00394                 rootElem = child;
00395             }  else  {
00396                 break;                                                        // done
00397             }
00398         }
00399         elements[rootElem] = rootValue;                                // complete swap
00400     }
00401 
00402     /*
00403      * Now: legit heap from the root on down
00404      * Not necessarily for the whole heap, since
00405      * we might be in the middle/early stages of
00406      * Heapify-ing a new (unordered) heap.
00407      */
00408     w_assert9(HeapProperty(rootElem));
00409 }
00410 
00411 template<class T, class Cmp>
00412 void Heap<T, Cmp>::SiftUp(int rootElem)
00413 {
00414     /*
00415      * Assumes: legit heap on down to just above rootElem
00416      */
00417     if(rootElem > 0) {
00418         w_assert9(HeapProperty(0, Parent(rootElem)));
00419     }
00420 
00421     if(rootElem > 0) {
00422         const T rootValue = elements[rootElem];
00423         int         i = rootElem;
00424         while (i > 0) { 
00425             if (cmp.gt(rootValue, elements[Parent(i)]))  {
00426                 // Swap : move down parent
00427                 elements[i] = elements[Parent(i)];
00428                 i = Parent(i);
00429             } else {
00430                 break;
00431             }
00432         }
00433         elements[i] = rootValue;                                // complete swap
00434     }
00435     /*  
00436      * Now: legit down to and including root Elem
00437      */
00438     w_assert9(HeapProperty(0, rootElem));
00439 }
00440 
00441 
00442 // creates a heap out of the unordered elements.
00443 //
00444 // start at bottom of the heap and form heaps out of all the
00445 // elements which have one child, then form heaps out of
00446 // these subheaps until the root of the tree is reached.
00447 //
00448 // this runs in O(n).
00449 
00450 template<class T, class Cmp>
00451 void Heap<T, Cmp>::Heapify()
00452 {
00453     if (NumElements() > 0)  {
00454         for (int i = Parent(NumElements() - 1); i >= 0; --i)  {
00455             SiftDown(i);
00456         }
00457 #if W_DEBUG_LEVEL > 2
00458         CheckHeap();
00459 #endif
00460     }
00461 }
00462 
00463 
00464 // Changes the elements array size.
00465 
00466 template<class T, class Cmp>
00467 void Heap<T, Cmp>::GrowElements(int newSize)
00468 {
00469     w_assert9(newSize >= numElements);
00470 
00471     T* newElements = new T[newSize];
00472     for (int i = 0; i < numElements; ++i)  {
00473         newElements[i] = elements[i];
00474     }
00475     delete[] elements;
00476     elements = newElements;
00477     maxNumElements = newSize;
00478 }
00479 
00480 
00481 // Verifies the heap condition of the elements array.
00482 
00483 template<class T, class Cmp>
00484 void Heap<T, Cmp>::CheckHeapRoot(int rootElem) const
00485 {
00486     if (rootElem < numElements)  {
00487         if (LeftChild(rootElem) < numElements)  {
00488             w_assert1(!cmp.gt(elements[LeftChild(rootElem)], 
00489                 elements[rootElem]));
00490             CheckHeapRoot(LeftChild(rootElem));
00491         }
00492         if (RightChild(rootElem) < numElements)  {
00493             w_assert1(!cmp.gt(elements[RightChild(rootElem)], 
00494                 elements[rootElem]));
00495             CheckHeapRoot(RightChild(rootElem));
00496         }
00497     }
00498 }
00499 
00500 template<class T, class Cmp>
00501 bool Heap<T, Cmp>::HeapProperty(int root) const
00502 {
00503     return HeapProperty(root, numElements);
00504 }
00505 
00506 // Check heap property from [top, bottom) i.e, NOT INCLUDING bottom
00507 // but including top.
00508 
00509 template<class T, class Cmp>
00510 bool Heap<T, Cmp>::HeapProperty(int top, int bottom) const
00511 {
00512    int last = (bottom > numElements) ? numElements : bottom;
00513 
00514    for(int i= LeftChild(top); i<last; i++) {
00515         if( cmp.gt( elements[i] , elements[Parent(i)] ) ) return false;
00516    }
00517    return true;
00518 }
00519 
00520 
00521 // Prints out the heap in a rotated tree format.
00522 
00523 template<class T, class Cmp>
00524 void Heap<T, Cmp>::PrintRoot(ostream& out, int rootElem, int indentLevel) const
00525 {
00526     if (rootElem < NumElements())  {
00527         PrintRoot(out, LeftChild(rootElem), indentLevel + 1);
00528         for (int i = 0; i < indentLevel; i++)  {
00529             cout << '\t';
00530         }
00531         cout << elements[rootElem] << '\n';
00532         PrintRoot(out, RightChild(rootElem), indentLevel + 1);
00533     }
00534 }
00535 
00536 /*<std-footer incl-file-exclusion='W_HEAP_H'>  -- do not edit anything below this line -- */
00537 
00538 #endif          /*</std-footer>*/

Generated on Mon Jan 2 15:13:57 2012 for Shore Storage Manager by  doxygen 1.4.7