AbstractHeap.h

00001 /*  _________________________________________________________________________
00002  *
00003  *  UTILIB: A utility library for developing portable C++ codes.
00004  *  Copyright (c) 2001, Sandia National Laboratories.
00005  *  This software is distributed under the GNU Lesser General Public License.
00006  *  For more information, see the README file in the top UTILIB directory.
00007  *  _________________________________________________________________________
00008  */
00009 
00010 //
00011 // AbstractHeap.h
00012 //
00024 #ifndef __AbstractHeap_h
00025 #define __AbstractHeap_h
00026 
00027 #ifdef __GNUC__
00028 #pragma interface
00029 #endif
00030 
00031 #ifdef NON_ANSI
00032 #include <iostream.h>
00033 #else
00034 #include <iostream>
00035 using namespace std;
00036 #endif
00037 
00038 #include "_generic.h"
00039 #include "errmsg.h"
00040 
00041 
00042 
00043 template <class T, class KEY>
00044 class AbstractHeap 
00045 {
00046 public:
00047 
00049   explicit AbstractHeap(const char* nameBuff = "Unnamed",
00050        int initSize = defaultSize, 
00051        int quantumChoice = defaultQuantum);
00053   virtual ~AbstractHeap();
00054   
00056   bool empty() const {return (used == 0);}
00058   operator bool() const {return (used != 0);}
00060   int size() const { return used; }
00061 
00063   OrderSense sense() {return Sense;}
00065   void setSense(OrderSense sense_) {Sense=sense_;}
00066 
00068   T* top() const
00069                 { 
00070                 if (used <= 0) 
00071                    cerr << "Empty heap: " << name << endl;
00072                 return tree[1]; 
00073                 }
00075   T* member(int element) const
00076                 { return tree[element]; }
00081   T* find(KEY& key);
00082 
00084   virtual void add(KEY& key)
00085                 {insert(&key);}
00090   virtual void add(KEY& key, T*& item)
00091                 {item = insert(&key);}
00097   virtual void remove(KEY& key, bool& status)
00098                 {
00099                 T* tmp = find(key);
00100                 if (tmp) extract(tmp,status);
00101                 else     status = false;
00102                 }
00108   virtual void remove(T*& item, bool& status)
00109                 {
00110                 if (!item)
00111                    status = false;
00112                 else {
00113                    extract(item,status);
00114                    item = 0;
00115                    }
00116                 }
00122   virtual void remove(T*& item, KEY& key, bool& status)
00123                 {
00124                 if (!item)
00125                    status = false;
00126                 else {
00127                    key = item->key();
00128                    extract(item,status);
00129                    item = 0;
00130                    }
00131                 }
00132 
00134   int write(ostream& os) const;
00136   int read(istream& is);
00137 
00139   int prune();
00140 
00142   static const int defaultSize;
00144   static const int defaultQuantum;
00146   void clear();
00147 
00148 protected:
00149 
00151   OrderSense Sense;
00152 
00154   virtual T* insert(KEY* item);
00160   virtual void extract(T* item, bool& status);
00162   int refloatElement(int element);
00163 
00165   virtual int  prunable(T* /*item*/) {return 0;}
00166 
00168   virtual void moveEffect(T* /*item*/) {}
00170   virtual void addEffect(T* /*item*/) {}
00172   virtual void removeEffect(T* item)
00173                 {item->element=0;}
00175   virtual void pruneEffect(T* /*item*/) {}
00176 
00178   int    used;
00180   int    allocated;
00182   int    quantum;
00184   T** tree;
00186   const char*  name;
00187 
00189   void swap(int a,int b);
00191   int floatUp(int element);
00193   int sinkDown(int element);
00194 
00195 };
00196 
00197 
00198 template <class T, class KEY>
00199 const int AbstractHeap<T,KEY>::defaultSize    = 256;
00200 template <class T, class KEY>
00201 const int AbstractHeap<T,KEY>::defaultQuantum = 256;
00202 
00203 template <class T, class KEY>
00204 inline ostream& operator<<(ostream& output, const AbstractHeap<T,KEY>& heap)
00205 { heap.write(output); return(output); }
00206 
00207 
00208  
00209 template <class T, class KEY>
00210 inline istream& operator>>(istream& input, AbstractHeap<T,KEY>& heap)
00211 { heap.read(input); return(input); }
00212 
00213 
00214 
00215 template <class T, class KEY>
00216 AbstractHeap<T,KEY>::AbstractHeap(const char* nameBuff,
00217            int initSize, 
00218            int quantumChoice) :
00219            Sense(increasing),
00220            used(0),
00221            allocated(initSize),
00222            quantum(quantumChoice),
00223            name(nameBuff)
00224 {
00225 if (!name)
00226    name = "";
00227 tree = (new (T*[initSize])) - 1;
00228 }
00229 
00230 
00231 template <class T, class KEY>
00232 AbstractHeap<T,KEY>::~AbstractHeap()
00233 {
00234 delete[] (tree + 1);
00235 }
00236 
00237 
00238 
00239 template <class T, class KEY>
00240 void AbstractHeap<T,KEY>::swap(int a,int b) 
00241 {
00242 register T* t1 = tree[a];
00243 register T* t2 = tree[b];
00244 tree[a] = t2;
00245 tree[b] = t1;
00246 t1->element=b;
00247 t2->element=a;
00248 moveEffect(t1);
00249 moveEffect(t2);
00250 }
00251 
00252 
00253 
00254 template <class T, class KEY>
00255 int AbstractHeap<T,KEY>::floatUp(int element)
00256 {
00257 int next;
00258 while (((next = element >> 1) >= 1) && 
00259        ((Sense* tree[element]->compare(tree[next]->key())) < 0))
00260   {
00261   swap(element,next);
00262   element = next;
00263   }
00264 return element;
00265 }
00266 
00267 
00268 template <class T, class KEY>
00269 int AbstractHeap<T,KEY>::sinkDown(int element)
00270 {
00271 int child;
00272 while ((child = element << 1) <= used) 
00273   {
00274   if ((child < used) && ((Sense*tree[child+1]->compare(tree[child]->key()))<0))
00275      child++;
00276   if ((Sense*tree[element]->compare(tree[child]->key()))<0)
00277      return(element);
00278   swap(element,child);
00279   element = child;
00280   }
00281 return element;
00282 }
00283 
00284 
00285 template <class T, class KEY>
00286 int AbstractHeap<T,KEY>::refloatElement(int element)
00287 {
00288 int newLocation = floatUp(element);
00289 if (newLocation == element)
00290    return sinkDown(element);
00291 else
00292    return element;
00293 }
00294 
00295 
00296 template <class T, class KEY>
00297 T* AbstractHeap<T,KEY>::insert(KEY* newkey) 
00298 {
00299 if (used == allocated) {
00300    if (quantum > 0) {
00301       allocated += quantum;
00302       T** oldTree = tree;
00303       tree = (new (T*[allocated])) - 1; 
00304       for (int i=1; i<=used; i++)
00305         tree[i] = oldTree[i];
00306       delete [] (oldTree + 1);
00307       }
00308    else 
00309       cerr << name << "heap overflowed at " << (used+1) << " elements" << endl;
00310    }
00311 
00312 T* item = new T(newkey);
00313 tree[++used] = item;
00314 addEffect(item);
00315 item->element=used;
00316 moveEffect(item);
00317 floatUp(used);
00318 return item;
00319 }
00320 
00321 
00322 template <class T, class KEY>
00323 void AbstractHeap<T,KEY>::extract(T* item, bool& status) 
00324 {
00325 int element = item->element;
00326 if ((element < 1) || (element > used)) {
00327    status=false;
00328    return;
00329    }
00330 
00331 removeEffect(item);
00332 delete item;
00333 if (element < used) {
00334    T* t = tree[used];
00335    tree[element] = t;
00336    used--;
00337    t->element=element;
00338    moveEffect(t);
00339    refloatElement(element);
00340    }
00341 else
00342    used--;
00343 
00344 status=true;
00345 }
00346 
00347 
00348 template <class T, class KEY>
00349 int AbstractHeap<T,KEY>::prune() 
00350 {
00351 int n = used;
00352 while (n > (used >> 1)) {
00353   if (prunable(tree[n])) {
00354      T* item = tree[n];
00355      pruneEffect(item);
00356      deleteElement(n);
00357      if (n > used)
00358         n = used;
00359      }
00360   else 
00361      n--;
00362   }
00363 return used;
00364 }
00365 
00366 
00367 template <class T, class KEY>
00368 int AbstractHeap<T,KEY>::write(ostream& os) const
00369 {
00370 os << size() << endl;
00371 for (int i=1; i<=size(); i++) {
00372   member(i)->write(os);
00373   os << endl;
00374   }
00375 os << endl;
00376 return OK;
00377 }
00378 
00379              
00380 template <class T, class KEY>
00381 int AbstractHeap<T,KEY>::read(istream& is)
00382 {
00383 clear();
00384 int Size;
00385 is >> Size;
00386 for (int i=1; i<=Size; i++) {
00387   T* item;
00388   item->read(is);
00389   add(item);
00390   }
00391 return OK;
00392 }          
00393 
00394 
00395 
00396 //
00397 // For right now, this is done with a linear search through the
00398 // heap array.  A more efficient method could be designed, but I don't
00399 // expect to use this method much, so...
00400 //
00401 template <class T, class KEY>
00402 T* AbstractHeap<T,KEY>::find(KEY& key)
00403 {
00404 for (int i=1; i<= size(); i++)
00405   if (member(i)->compare(key) == 0)
00406      return member(i);
00407 
00408 return 0;
00409 }
00410 
00411 
00412 template <class T, class KEY>
00413 void AbstractHeap<T,KEY>::clear()
00414 {
00415 bool status;
00416 while (size()>0) {
00417   remove(top(),status);
00418   if (!status)
00419      ErrAbort("AbstractHeap<T,KEY>::clear - problem removing the root of the heap.");
00420   }
00421 }
00422 
00423 
00424 #endif