Grafalgo
Library of useful data structures and algorithms
|
00001 00009 #include "StairFunc.h" 00010 00011 namespace grafalgo { 00012 00016 StairFunc::StairFunc(int size) : Adt(size) { 00017 makeSpace(size); 00018 } 00019 00021 StairFunc::~StairFunc() { freeSpace(); } 00022 00026 void StairFunc::makeSpace(int size) { 00027 try { 00028 points = new DkBstSet(2*size+1); free = new List(2*size+1); 00029 } catch (std::bad_alloc e) { 00030 stringstream ss; 00031 ss << "makeSpace:: insufficient space for " 00032 << size << "index values"; 00033 string s = ss.str(); 00034 throw OutOfSpaceException(s); 00035 } 00036 nn = size; clear(); 00037 } 00038 00040 void StairFunc::freeSpace() { delete points; delete free; } 00041 00046 void StairFunc::clear() { 00047 points->clear(); free->clear(); 00048 points->setkey(1,0,0); // initialize function to zero for all x>=0 00049 for (int i = 2; i <= 2*n()+1; i++) free->addLast(i); 00050 } 00051 00055 void StairFunc::resize(int size) { 00056 freeSpace(); 00057 try { makeSpace(size); } catch(OutOfSpaceException e) { 00058 string s; s = "StairFunc::resize::" + e.toString(s); 00059 throw OutOfSpaceException(s); 00060 } 00061 } 00062 00067 void StairFunc::expand(int size) { 00068 if (size <= n()) return; 00069 StairFunc old(this->n()); old.copyFrom(*this); 00070 resize(size); this->copyFrom(old); 00071 } 00072 00076 void StairFunc::copyFrom(const StairFunc& source) { 00077 if (&source == this) return; 00078 if (source.n() > n()) resize(source.n()); 00079 else clear(); 00080 00081 points->copyFrom(*(source.points)); 00082 free->copyFrom(*(source.free)); 00083 } 00084 00085 // Return the y value at a specified x coordinate 00086 index StairFunc::value(int x) { 00087 assert (x >= 0); 00088 index v = points->access(x,points->find(1)); 00089 return points->key2(v); 00090 } 00091 00092 // Return the smallest y value that the function takes on in 00093 // the range [lo,hi] 00094 int StairFunc::findmin(int lo, int hi) { 00095 assert(0 <= lo && lo <= hi); 00096 int min = Util::BIGINT32; 00097 BstSet::BstPair pairA(0,0); BstSet::BstPair pairB(0,0); 00098 00099 //lowNode is largest node with key1 <= lo 00100 index lowNode = points->access(lo,points->find(1)); 00101 //split at lowNode, stuff we want in pairA.t2 00102 pairA = points->split(lowNode, points->find(1)); 00103 //if key1(lowNode) == lo, we should include it 00104 if(points->key1(lowNode) >= lo){ min = points->key2(lowNode);} 00105 00106 //we have 3 trees now, pair.t1, lo, pair.t2 00107 //within pair.t2, split at the largest node < hi 00108 index hiNode = points->access(hi, points->find(pairA.t2)); 00109 pairB = points->split(hiNode, points->find(pairA.t2)); 00110 //check if min is at hiNode (hiNode <= hi) 00111 if(points->key2(hiNode) < min){ min = points->key2(hiNode);} 00112 00113 //last thing to check is min in pairB.t1 00114 if(points->min2(pairB.t1) < min){ min = points->min2(pairB.t1);} 00115 00116 //reassemble the parts...we have 5 trees now 00117 int hiPortion = points->join(pairB.t1, hiNode, pairB.t2); 00118 points->join(pairA.t1, lowNode, hiPortion); 00119 00120 return min; 00121 } 00122 00123 // Add diff to all values in the range lo,hi. 00124 void StairFunc::change(int lo, int hi, int diff) { 00125 assert(0 <= lo && lo <= hi); 00126 // when adding new points to the function, first select unused index 00127 // from free list and insert that point into points 00128 // after removing an index from points, put it back on free 00129 // note - never remove index #1 from the search tree 00130 BstSet::BstPair pairA(0,0); BstSet::BstPair pairB(0,0); 00131 00132 //lowNode is largest node with key1 <= lo 00133 index lowNode = points->access(lo,points->find(1)); 00134 //split at lowNode and hiNode, like findmin func 00135 pairA = points->split(lowNode, points->find(1)); 00136 index hiNode = points->access(hi, points->find(pairA.t2)); 00137 if(pairA.t2 != 0){ 00138 pairB = points->split(hiNode, points->find(pairA.t2)); 00139 } 00140 00141 //handle edge cases 00142 index insertLo, insertHi; 00143 //if lo == lowNode, add diff to lowNode, don't insert 00144 if (lo == lowNode) { 00145 points->change2(diff, points->find(lowNode)); 00146 } else { 00147 insertLo = free->first(); free->removeFirst(); 00148 points->setkey(insertLo, lo, diff + points->key2(lowNode)); 00149 if (points->find(pairA.t2) == 0){ 00150 points->insert(insertLo, points->find(lowNode)); 00151 } else { 00152 points->insert(insertLo, points->find(pairA.t2)); 00153 } 00154 } 00155 //if hi == hiNode, add diff to hiNode, don't insert 00156 if (hi == hiNode) { 00157 points->change2(diff, points->find(hiNode)); 00158 }else{ 00159 insertHi = free->first(); free->removeFirst(); 00160 if(hi>hiNode){//at rightmost of step func 00161 points->setkey(insertHi, hi+1, 0); 00162 } else { 00163 points->setkey(insertHi, hi+1, 00164 diff + points->key2(hiNode)); 00165 } 00166 if (points->find(pairB.t1 != 0)){ 00167 points->insert(insertHi, points->find(pairB.t1)); 00168 } else if (hiNode != 0){ 00169 points->insert(insertHi, points->find(hiNode)); 00170 } else { 00171 points->insert(insertHi, points->find(lowNode)); 00172 } 00173 } 00174 00175 //everything in pairB.t1 is within range, add diff to dmin 00176 if(pairB.t1 != 0){ 00177 points->change2(diff, points->find(pairB.t1)); 00178 } 00179 00180 //resemble the parts...we got 5 trees now 00181 int hiPortion = 0; 00182 if(hiNode != 0){ 00183 hiPortion = points->join(pairB.t1, hiNode, pairB.t2); 00184 } 00185 points->join(pairA.t1, lowNode, hiPortion); 00186 } 00187 00188 string& StairFunc::toString(string& s) const { 00189 stringstream ss; 00190 for (index i = 1; i != 0; i = points->suc(i)) { 00191 ss << "(" << points->key1(i) << "," << points->key2(i) << ") "; 00192 } 00193 ss << "\n"; 00194 s = ss.str(); 00195 return s; 00196 } 00197 00198 } // ends namespace