eavlmmap.h

00001 //
00002 // eavlmmap.h --- definition for embedded avl multimap class
00003 //
00004 // Copyright (C) 1996 Limit Point Systems, Inc.
00005 //
00006 // Author: Curtis Janssen <cljanss@limitpt.com>
00007 // Maintainer: LPS
00008 //
00009 // This file is part of the SC Toolkit.
00010 //
00011 // The SC Toolkit is free software; you can redistribute it and/or modify
00012 // it under the terms of the GNU Library General Public License as published by
00013 // the Free Software Foundation; either version 2, or (at your option)
00014 // any later version.
00015 //
00016 // The SC Toolkit is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 // GNU Library General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU Library General Public License
00022 // along with the SC Toolkit; see the file COPYING.LIB.  If not, write to
00023 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
00024 //
00025 // The U.S. Government is granted a limited license as per AL 91-7.
00026 //
00027 
00028 #ifndef _util_container_eavlmmap_h
00029 #define _util_container_eavlmmap_h
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #  include <scconfig.h>
00033 #endif
00034 #include <iostream>
00035 #include <util/misc/exenv.h>
00036 #include <util/container/compare.h>
00037 #include <unistd.h> // for size_t on solaris
00038 #include <stdlib.h>
00039 
00040 #ifdef __GNUC__
00041 // gcc typename seems to be broken in some cases
00042 #  define eavl_typename
00043 #else
00044 #  define eavl_typename typename
00045 #endif
00046 
00047 namespace sc {
00048 
00049 template <class K, class T>
00050 class EAVLMMapNode {
00051   public:
00052     K key;
00053     T* lt;
00054     T* rt;
00055     T* up;
00056     int balance;
00057   public:
00058     EAVLMMapNode(const K& k): key(k) {}
00059 };
00060 
00061 template <class K, class T>
00062 class EAVLMMap {
00063   private:
00064     size_t length_;
00065     T *root_;
00066     T *start_;
00067     EAVLMMapNode<K,T> T::* node_;
00068   public:
00069     T*& rlink(T* n) const { return (n->*node_).rt; }
00070     T* rlink(const T* n) const { return (n->*node_).rt; }
00071     T*& llink(T* n) const { return (n->*node_).lt; }
00072     T* llink(const T* n) const { return (n->*node_).lt; }
00073     T*& uplink(T* n) const { return (n->*node_).up; }
00074     T* uplink(const T* n) const { return (n->*node_).up; }
00075     int& balance(T* n) const { return (n->*node_).balance; }
00076     int balance(const T* n) const { return (n->*node_).balance; }
00077     K& key(T* n) const { return (n->*node_).key; }
00078     const K& key(const T* n) const { return (n->*node_).key; }
00079     int compare(T*n,T*m) const { return sc::compare(key(n), key(m)); }
00080     int compare(T*n,const K&m) const { return sc::compare(key(n), m); }
00081   private:
00082     void adjust_balance_insert(T* A, T* child);
00083     void adjust_balance_remove(T* A, T* child);
00084     void clear(T*);
00085   public:
00086     class iterator {
00087       private:
00088         EAVLMMap<K,T> *map_;
00089         T *node;
00090       public:
00091         iterator(EAVLMMap<K,T> *m, T *n):map_(m),node(n){}
00092         iterator(const eavl_typename EAVLMMap<K,T>::iterator &i) { map_=i.map_; node=i.node; }
00093         void operator++() { map_->next(node); }
00094         void operator++(int) { operator++(); }
00095         int operator == (const eavl_typename EAVLMMap<K,T>::iterator &i) const
00096             { return map_ == i.map_ && node == i.node; }
00097         int operator != (const eavl_typename EAVLMMap<K,T>::iterator &i) const
00098             { return !operator == (i); }
00099         void operator = (const eavl_typename EAVLMMap<K,T>::iterator &i)
00100             { map_ = i.map_; node = i.node; }
00101         const K &key() const { return map_->key(node); }
00102         T & operator *() { return *node; }
00103         T * operator->() { return node; }
00104     };
00105   public:
00106     EAVLMMap();
00107     EAVLMMap(EAVLMMapNode<K,T> T::* node);
00108     ~EAVLMMap() { clear(root_); }
00109     void initialize(EAVLMMapNode<K,T> T::* node);
00110     void clear_without_delete() { initialize(node_); }
00111     void clear() { clear(root_); initialize(node_); }
00112     void insert(T*);
00113     void remove(T*);
00114     T* find(const K&) const;
00115 
00116     int height(T* node);
00117     int height() { return height(root_); }
00118     void check();
00119     void check_node(T*) const;
00120 
00121     T* start() const { return start_; }
00122     void next(const T*&) const;
00123     void next(T*&) const;
00124 
00125     iterator begin() { return iterator(this,start()); }
00126     iterator end() { return iterator(this,0); }
00127 
00128     void print() const;
00129     void detailed_print() const;
00130     int length() const { return length_; }
00131     int depth(T*) const;
00132 };
00133 
00134 template <class K, class T>
00135 T*
00136 EAVLMMap<K,T>::find(const K& key) const
00137 {
00138   T* n = root_;
00139 
00140   while (n) {
00141       int cmp = compare(n, key);
00142       if (cmp < 0) n = rlink(n);
00143       else if (cmp > 0) n = llink(n);
00144       else return n;
00145     }
00146 
00147   return 0;
00148 }
00149 
00150 template <class K, class T>
00151 void
00152 EAVLMMap<K,T>::remove(T* node)
00153 {
00154   if (!node) return;
00155 
00156   length_--;
00157 
00158   if (node == start_) {
00159       next(start_);
00160     }
00161 
00162   T *rebalance_point;
00163   T *q;
00164 
00165   if (llink(node) == 0) {
00166       q = rlink(node);
00167       rebalance_point = uplink(node);
00168 
00169       if (q) uplink(q) = rebalance_point;
00170 
00171       if (rebalance_point) {
00172           if (rlink(rebalance_point) == node) rlink(rebalance_point) = q;
00173           else llink(rebalance_point) = q;
00174         }
00175       else root_ = q;
00176     }
00177   else if (rlink(node) == 0) {
00178       q = llink(node);
00179       rebalance_point = uplink(node);
00180 
00181       if (q) uplink(q) = rebalance_point;
00182 
00183       if (rebalance_point) {
00184           if (rlink(rebalance_point) == node) rlink(rebalance_point) = q;
00185           else llink(rebalance_point) = q;
00186         }
00187       else root_ = q;
00188     }
00189   else {
00190       T *r = node;
00191       next(r);
00192 
00193       if (r == 0 || llink(r) != 0) {
00194           ExEnv::errn() << "EAVLMMap::remove: inconsistency" << std::endl;
00195           abort();
00196         }
00197 
00198       if (r == rlink(node)) {
00199           llink(r) = llink(node);
00200           if (llink(r)) uplink(llink(r)) = r;
00201           balance(r) = balance(node);
00202           rebalance_point = r;
00203           q = rlink(r);
00204         }
00205       else {
00206           q = rlink(r);
00207 
00208           rebalance_point = uplink(r);
00209 
00210           if (llink(rebalance_point) == r) llink(rebalance_point) = q;
00211           else rlink(rebalance_point) = q;
00212 
00213           if (q) uplink(q) = rebalance_point;
00214 
00215           balance(r) = balance(node);
00216           rlink(r) = rlink(node);
00217           llink(r) = llink(node);
00218           if (rlink(r)) uplink(rlink(r)) = r;
00219           if (llink(r)) uplink(llink(r)) = r;
00220         }
00221       if (r) {
00222           T* up = uplink(node);
00223           uplink(r) = up;
00224           if (up) {
00225               if (rlink(up) == node) rlink(up) = r;
00226               else llink(up) = r;
00227             }
00228           if (up == 0) root_ = r;
00229         }
00230     }
00231 
00232   // adjust balance won't work if both children are null,
00233   // so handle this special case here
00234   if (rebalance_point &&
00235       llink(rebalance_point) == 0 && rlink(rebalance_point) == 0) {
00236       balance(rebalance_point) = 0;
00237       q = rebalance_point;
00238       rebalance_point = uplink(rebalance_point);
00239     }
00240   adjust_balance_remove(rebalance_point, q);
00241 }
00242 
00243 template <class K, class T>
00244 void
00245 EAVLMMap<K,T>::print() const
00246 {
00247   for (T*n=start(); n; next(n)) {
00248       int d = depth(n) + 1;
00249       for (int i=0; i<d; i++) ExEnv::out0() << "     ";
00250       if (balance(n) == 1) ExEnv::out0() << " (+)" << std::endl;
00251       else if (balance(n) == -1) ExEnv::out0() << " (-)" << std::endl;
00252       else if (balance(n) == 0) ExEnv::out0() << " (.)" << std::endl;
00253       else ExEnv::out0() << " (" << balance(n) << ")" << std::endl;
00254     }
00255 }
00256 
00257 template <class K, class T>
00258 void
00259 EAVLMMap<K,T>::detailed_print() const
00260 {
00261   for (T*n=start(); n; next(n)) {
00262       int d = depth(n) + 1;
00263       for (int i=0; i<d; i++) ExEnv::out0() << "     ";
00264       if (balance(n) == 1) ExEnv::out0() << " (+) "
00265                                          << key(n) << std::endl;
00266       else if (balance(n) == -1) ExEnv::out0() << " (-) "
00267                                                << key(n) << std::endl;
00268       else if (balance(n) == 0) ExEnv::out0() << " (.) "
00269                                               << key(n) << std::endl;
00270       else ExEnv::out0() << " (" << balance(n) << ") "
00271                          << key(n) << std::endl;
00272     }
00273 }
00274 
00275 template <class K, class T>
00276 int
00277 EAVLMMap<K,T>::depth(T*node) const
00278 {
00279   int d = 0;
00280   while (node) {
00281       node = uplink(node);
00282       d++;
00283     }
00284   return d;
00285 }
00286 
00287 template <class K, class T>
00288 void
00289 EAVLMMap<K,T>::check_node(T*n) const
00290 {
00291   if (uplink(n) && uplink(n) == n) abort();
00292   if (llink(n) && llink(n) == n) abort();
00293   if (rlink(n) && rlink(n) == n) abort();
00294   if (rlink(n) && rlink(n) == llink(n)) abort();
00295   if (uplink(n) && uplink(n) == llink(n)) abort();
00296   if (uplink(n) && uplink(n) == rlink(n)) abort();
00297   if (uplink(n) && !(llink(uplink(n)) == n
00298                      || rlink(uplink(n)) == n)) abort();
00299 }
00300 
00301 template <class K, class T>
00302 void
00303 EAVLMMap<K,T>::clear(T*n)
00304 {
00305   if (!n) return;
00306   clear(llink(n));
00307   clear(rlink(n));
00308   delete n;
00309 }
00310 
00311 template <class K, class T>
00312 int
00313 EAVLMMap<K,T>::height(T* node)
00314 {
00315   if (!node) return 0;
00316   int rh = height(rlink(node)) + 1;
00317   int lh = height(llink(node)) + 1;
00318   return rh>lh?rh:lh;
00319 }
00320 
00321 template <class K, class T>
00322 void
00323 EAVLMMap<K,T>::check()
00324 {
00325   T* node;
00326   T* prev=0;
00327   size_t computed_length = 0;
00328   for (node = start(); node; next(node)) {
00329       check_node(node);
00330       if (prev && compare(prev,node) > 0) {
00331           ExEnv::errn() << "nodes out of order" << std::endl;
00332           abort();
00333         }
00334       prev = node;
00335       computed_length++;
00336     }
00337   for (node = start(); node; next(node)) {
00338       if (balance(node) != height(rlink(node)) - height(llink(node))) {
00339           ExEnv::errn() << "balance inconsistency" << std::endl;
00340           abort();
00341         }
00342       if (balance(node) < -1 || balance(node) > 1) {
00343           ExEnv::errn() << "balance out of range" << std::endl;
00344           abort();
00345         }
00346     }
00347   if (length_ != computed_length) {
00348       ExEnv::errn() << "length error" << std::endl;
00349       abort();
00350     }
00351 }
00352 
00353 template <class K, class T>
00354 void
00355 EAVLMMap<K,T>::next(const T*& node) const
00356 {
00357   const T* r;
00358   if (r = rlink(node)) {
00359       node = r;
00360       while (r = llink(node)) node = r;
00361       return;
00362     }
00363   while (r = uplink(node)) {
00364       if (node == llink(r)) {
00365           node = r;
00366           return;
00367         }
00368       node = r;
00369     }
00370   node = 0;
00371 }
00372 
00373 template <class K, class T>
00374 void
00375 EAVLMMap<K,T>::next(T*& node) const
00376 {
00377   T* r;
00378   if (r = rlink(node)) {
00379       node = r;
00380       while (r = llink(node)) node = r;
00381       return;
00382     }
00383   while (r = uplink(node)) {
00384       if (node == llink(r)) {
00385           node = r;
00386           return;
00387         }
00388       node = r;
00389     }
00390   node = 0;
00391 }
00392 
00393 template <class K, class T>
00394 void
00395 EAVLMMap<K,T>::insert(T* n)
00396 {
00397   if (!n) {
00398       return;
00399     }
00400 
00401   length_++;
00402 
00403   rlink(n) = 0;
00404   llink(n) = 0;
00405   balance(n) = 0;
00406 
00407   if (!root_) {
00408       uplink(n) = 0;
00409       root_ = n;
00410       start_ = n;
00411       return;
00412     }
00413 
00414   // find an insertion point
00415   T* p = root_;
00416   T* prev_p = 0;
00417   int cmp;
00418   int have_start = 1;
00419   while (p) {
00420       if (p == n) {
00421           abort();
00422         }
00423       prev_p = p;
00424       cmp = compare(n,p);
00425       if (cmp < 0) p = llink(p);
00426       else {
00427           p = rlink(p);
00428           have_start = 0;
00429         }
00430     }
00431 
00432   // insert the node
00433   uplink(n) = prev_p;
00434   if (prev_p) {
00435       if (cmp < 0) llink(prev_p) = n;
00436       else rlink(prev_p) = n;
00437     }
00438 
00439   // maybe update the first node in the map
00440   if (have_start) start_ = n;
00441 
00442   // adjust the balance factors
00443   if (prev_p) {
00444       adjust_balance_insert(prev_p, n);
00445     }
00446 }
00447 
00448 template <class K, class T>
00449 void
00450 EAVLMMap<K,T>::adjust_balance_insert(T* A, T* child)
00451 {
00452   if (!A) return;
00453   int adjustment;
00454   if (llink(A) == child) adjustment = -1;
00455   else adjustment = 1;
00456   int bal = balance(A) + adjustment;
00457   if (bal == 0) {
00458       balance(A) = 0;
00459     }
00460   else if (bal == -1 || bal == 1) {
00461       balance(A) = bal;
00462       adjust_balance_insert(uplink(A), A);
00463     }
00464   else if (bal == 2) {
00465       T* B = rlink(A);
00466       if (balance(B) == 1) {
00467           balance(B) = 0;
00468           balance(A) = 0;
00469           rlink(A) = llink(B);
00470           llink(B) = A;
00471           uplink(B) = uplink(A);
00472           uplink(A) = B;
00473           if (rlink(A)) uplink(rlink(A)) = A;
00474           if (llink(B)) uplink(llink(B)) = B;
00475           if (uplink(B) == 0) root_ = B;
00476           else {
00477               if (rlink(uplink(B)) == A) rlink(uplink(B)) = B;
00478               else llink(uplink(B)) = B;
00479             }
00480         }
00481       else {
00482           T* X = llink(B);
00483           rlink(A) = llink(X);
00484           llink(B) = rlink(X);
00485           llink(X) = A;
00486           rlink(X) = B;
00487           if (balance(X) == 1) {
00488               balance(A) = -1;
00489               balance(B) = 0;
00490             }
00491           else if (balance(X) == -1) {
00492               balance(A) = 0;
00493               balance(B) = 1;
00494             }
00495           else {
00496               balance(A) = 0;
00497               balance(B) = 0;
00498             }
00499           balance(X) = 0;
00500           uplink(X) = uplink(A);
00501           uplink(A) = X;
00502           uplink(B) = X;
00503           if (rlink(A)) uplink(rlink(A)) = A;
00504           if (llink(B)) uplink(llink(B)) = B;
00505           if (uplink(X) == 0) root_ = X;
00506           else {
00507               if (rlink(uplink(X)) == A) rlink(uplink(X)) = X;
00508               else llink(uplink(X)) = X;
00509             }
00510         }
00511     }
00512   else if (bal == -2) {
00513       T* B = llink(A);
00514       if (balance(B) == -1) {
00515           balance(B) = 0;
00516           balance(A) = 0;
00517           llink(A) = rlink(B);
00518           rlink(B) = A;
00519           uplink(B) = uplink(A);
00520           uplink(A) = B;
00521           if (llink(A)) uplink(llink(A)) = A;
00522           if (rlink(B)) uplink(rlink(B)) = B;
00523           if (uplink(B) == 0) root_ = B;
00524           else {
00525               if (llink(uplink(B)) == A) llink(uplink(B)) = B;
00526               else rlink(uplink(B)) = B;
00527             }
00528         }
00529       else {
00530           T* X = rlink(B);
00531           llink(A) = rlink(X);
00532           rlink(B) = llink(X);
00533           rlink(X) = A;
00534           llink(X) = B;
00535           if (balance(X) == -1) {
00536               balance(A) = 1;
00537               balance(B) = 0;
00538             }
00539           else if (balance(X) == 1) {
00540               balance(A) = 0;
00541               balance(B) = -1;
00542             }
00543           else {
00544               balance(A) = 0;
00545               balance(B) = 0;
00546             }
00547           balance(X) = 0;
00548           uplink(X) = uplink(A);
00549           uplink(A) = X;
00550           uplink(B) = X;
00551           if (llink(A)) uplink(llink(A)) = A;
00552           if (rlink(B)) uplink(rlink(B)) = B;
00553           if (uplink(X) == 0) root_ = X;
00554           else {
00555               if (llink(uplink(X)) == A) llink(uplink(X)) = X;
00556               else rlink(uplink(X)) = X;
00557             }
00558         }
00559     }
00560 }
00561 
00562 template <class K, class T>
00563 void
00564 EAVLMMap<K,T>::adjust_balance_remove(T* A, T* child)
00565 {
00566   if (!A) return;
00567   int adjustment;
00568   if (llink(A) == child) adjustment = 1;
00569   else adjustment = -1;
00570   int bal = balance(A) + adjustment;
00571   if (bal == 0) {
00572       balance(A) = 0;
00573       adjust_balance_remove(uplink(A), A);
00574     }
00575   else if (bal == -1 || bal == 1) {
00576       balance(A) = bal;
00577     }
00578   else if (bal == 2) {
00579       T* B = rlink(A);
00580       if (balance(B) == 0) {
00581           balance(B) = -1;
00582           balance(A) = 1;
00583           rlink(A) = llink(B);
00584           llink(B) = A;
00585           uplink(B) = uplink(A);
00586           uplink(A) = B;
00587           if (rlink(A)) uplink(rlink(A)) = A;
00588           if (llink(B)) uplink(llink(B)) = B;
00589           if (uplink(B) == 0) root_ = B;
00590           else {
00591               if (rlink(uplink(B)) == A) rlink(uplink(B)) = B;
00592               else llink(uplink(B)) = B;
00593             }
00594         }
00595       else if (balance(B) == 1) {
00596           balance(B) = 0;
00597           balance(A) = 0;
00598           rlink(A) = llink(B);
00599           llink(B) = A;
00600           uplink(B) = uplink(A);
00601           uplink(A) = B;
00602           if (rlink(A)) uplink(rlink(A)) = A;
00603           if (llink(B)) uplink(llink(B)) = B;
00604           if (uplink(B) == 0) root_ = B;
00605           else {
00606               if (rlink(uplink(B)) == A) rlink(uplink(B)) = B;
00607               else llink(uplink(B)) = B;
00608             }
00609           adjust_balance_remove(uplink(B), B);
00610         }
00611       else {
00612           T* X = llink(B);
00613           rlink(A) = llink(X);
00614           llink(B) = rlink(X);
00615           llink(X) = A;
00616           rlink(X) = B;
00617           if (balance(X) == 0) {
00618               balance(A) = 0;
00619               balance(B) = 0;
00620             }
00621           else if (balance(X) == 1) {
00622               balance(A) = -1;
00623               balance(B) = 0;
00624             }
00625           else {
00626               balance(A) = 0;
00627               balance(B) = 1;
00628             }
00629           balance(X) = 0;
00630           uplink(X) = uplink(A);
00631           uplink(A) = X;
00632           uplink(B) = X;
00633           if (rlink(A)) uplink(rlink(A)) = A;
00634           if (llink(B)) uplink(llink(B)) = B;
00635           if (uplink(X) == 0) root_ = X;
00636           else {
00637               if (rlink(uplink(X)) == A) rlink(uplink(X)) = X;
00638               else llink(uplink(X)) = X;
00639             }
00640           adjust_balance_remove(uplink(X), X);
00641         }
00642     }
00643   else if (bal == -2) {
00644       T* B = llink(A);
00645       if (balance(B) == 0) {
00646           balance(B) = 1;
00647           balance(A) = -1;
00648           llink(A) = rlink(B);
00649           rlink(B) = A;
00650           uplink(B) = uplink(A);
00651           uplink(A) = B;
00652           if (llink(A)) uplink(llink(A)) = A;
00653           if (rlink(B)) uplink(rlink(B)) = B;
00654           if (uplink(B) == 0) root_ = B;
00655           else {
00656               if (llink(uplink(B)) == A) llink(uplink(B)) = B;
00657               else rlink(uplink(B)) = B;
00658             }
00659         }
00660       else if (balance(B) == -1) {
00661           balance(B) = 0;
00662           balance(A) = 0;
00663           llink(A) = rlink(B);
00664           rlink(B) = A;
00665           uplink(B) = uplink(A);
00666           uplink(A) = B;
00667           if (llink(A)) uplink(llink(A)) = A;
00668           if (rlink(B)) uplink(rlink(B)) = B;
00669           if (uplink(B) == 0) root_ = B;
00670           else {
00671               if (llink(uplink(B)) == A) llink(uplink(B)) = B;
00672               else rlink(uplink(B)) = B;
00673             }
00674           adjust_balance_remove(uplink(B), B);
00675         }
00676       else {
00677           T* X = rlink(B);
00678           llink(A) = rlink(X);
00679           rlink(B) = llink(X);
00680           rlink(X) = A;
00681           llink(X) = B;
00682           if (balance(X) == 0) {
00683               balance(A) = 0;
00684               balance(B) = 0;
00685             }
00686           else if (balance(X) == -1) {
00687               balance(A) = 1;
00688               balance(B) = 0;
00689             }
00690           else {
00691               balance(A) = 0;
00692               balance(B) = -1;
00693             }
00694           balance(X) = 0;
00695           uplink(X) = uplink(A);
00696           uplink(A) = X;
00697           uplink(B) = X;
00698           if (llink(A)) uplink(llink(A)) = A;
00699           if (rlink(B)) uplink(rlink(B)) = B;
00700           if (uplink(X) == 0) root_ = X;
00701           else {
00702               if (llink(uplink(X)) == A) llink(uplink(X)) = X;
00703               else rlink(uplink(X)) = X;
00704             }
00705           adjust_balance_remove(uplink(X), X);
00706         }
00707     }
00708 }
00709 
00710 template <class K, class T>
00711 inline
00712 EAVLMMap<K,T>::EAVLMMap()
00713 {
00714   initialize(0);
00715 }
00716 
00717 template <class K, class T>
00718 inline
00719 EAVLMMap<K,T>::EAVLMMap(EAVLMMapNode<K,T> T::* node)
00720 {
00721   initialize(node);
00722 }
00723 
00724 template <class K, class T>
00725 inline void
00726 EAVLMMap<K,T>::initialize(EAVLMMapNode<K,T> T::* node)
00727 {
00728   node_ = node;
00729   root_ = 0;
00730   start_ = 0;
00731   length_ = 0;
00732 }
00733 
00734 }
00735 
00736 #endif
00737 
00738 // ///////////////////////////////////////////////////////////////////////////
00739 
00740 // Local Variables:
00741 // mode: c++
00742 // c-file-style: "CLJ"
00743 // End:

Generated at Wed Sep 5 14:02:29 2007 for MPQC 3.0.0-alpha using the documentation package Doxygen 1.5.2.
These pages are hosted on SourceForge.net