00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef LEMON_RADIX_HEAP_H
00018 #define LEMON_RADIX_HEAP_H
00019
00023
00024 #include <vector>
00025 #include <lemon/error.h>
00026
00027 namespace lemon {
00028
00031
00038
00039 class UnderFlowPriorityError : public RuntimeError {
00040 public:
00041 virtual const char* exceptionName() const {
00042 return "lemon::UnderFlowPriorityError";
00043 }
00044 };
00045
00063
00064 template <typename _Item, typename _ItemIntMap>
00065 class RadixHeap {
00066
00067 public:
00068 typedef _Item Item;
00069 typedef int Prio;
00070 typedef _ItemIntMap ItemIntMap;
00071
00080 enum state_enum {
00081 IN_HEAP = 0,
00082 PRE_HEAP = -1,
00083 POST_HEAP = -2
00084 };
00085
00086 private:
00087
00088 struct RadixItem {
00089 int prev, next, box;
00090 Item item;
00091 int prio;
00092 RadixItem(Item _item, int _prio) : item(_item), prio(_prio) {}
00093 };
00094
00095 struct RadixBox {
00096 int first;
00097 int min, size;
00098 RadixBox(int _min, int _size) : first(-1), min(_min), size(_size) {}
00099 };
00100
00101 std::vector<RadixItem> data;
00102 std::vector<RadixBox> boxes;
00103
00104 ItemIntMap &iim;
00105
00106
00107 public:
00114 explicit RadixHeap(ItemIntMap &_iim) : iim(_iim) {
00115 boxes.push_back(RadixBox(0, 1));
00116 boxes.push_back(RadixBox(1, 1));
00117 }
00118
00128 RadixHeap(ItemIntMap &_iim, int capacity) : iim(_iim) {
00129 boxes.push_back(RadixBox(0, 1));
00130 boxes.push_back(RadixBox(1, 1));
00131 while (upper(boxes.back(), capacity)) {
00132 extend();
00133 }
00134 }
00135
00139 int size() const { return data.size(); }
00143 bool empty() const { return data.empty(); }
00144
00145 private:
00146
00147 bool upper(int box, Prio prio) {
00148 return prio < boxes[box].min;
00149 }
00150
00151 bool lower(int box, Prio prio) {
00152 return prio >= boxes[box].min + boxes[box].size;
00153 }
00154
00156 void remove(int index) {
00157 if (data[index].prev >= 0) {
00158 data[data[index].prev].next = data[index].next;
00159 } else {
00160 boxes[data[index].box].first = data[index].next;
00161 }
00162 if (data[index].next >= 0) {
00163 data[data[index].next].prev = data[index].prev;
00164 }
00165 }
00166
00168 void insert(int box, int index) {
00169 if (boxes[box].first == -1) {
00170 boxes[box].first = index;
00171 data[index].next = data[index].prev = -1;
00172 } else {
00173 data[index].next = boxes[box].first;
00174 data[boxes[box].first].prev = index;
00175 data[index].prev = -1;
00176 boxes[box].first = index;
00177 }
00178 data[index].box = box;
00179 }
00180
00182 void extend() {
00183 int min = boxes.back().min + boxes.back().size;
00184 int size = 2 * boxes.back().size;
00185 boxes.push_back(RadixBox(min, size));
00186 }
00187
00189 void bubble_up(int index) {
00190 if (!lower(data[index].box, data[index].prio)) return;
00191 remove(index);
00192 int box = findUp(data[index].box, data[index].prio);
00193 insert(box, index);
00194 }
00195
00197 int findUp(int start, int prio) {
00198 while (lower(start, prio)) {
00199 if (++start == (int)boxes.size()) {
00200 extend();
00201 }
00202 }
00203 return start;
00204 }
00205
00207 void bubble_down(int index) {
00208 if (!upper(data[index].box, data[index].prio)) return;
00209 remove(index);
00210 int box = findDown(data[index].box, data[index].prio);
00211 insert(box, index);
00212 }
00213
00215 int findDown(int start, int prio) {
00216 while (upper(start, prio)) {
00217 if (--start < 0) throw UnderFlowPriorityError();
00218 }
00219 return start;
00220 }
00221
00223 int findFirst() {
00224 int first = 0;
00225 while (boxes[first].first == -1) ++first;
00226 return first;
00227 }
00228
00230 int minValue(int box) {
00231 int min = data[boxes[box].first].prio;
00232 for (int k = boxes[box].first; k != -1; k = data[k].next) {
00233 if (data[k].prio < min) min = data[k].prio;
00234 }
00235 return min;
00236 }
00237
00240 void moveDown() {
00241 int box = findFirst();
00242 if (box == 0) return;
00243 int min = minValue(box);
00244 for (int i = 0; i <= box; ++i) {
00245 boxes[i].min = min;
00246 min += boxes[i].size;
00247 }
00248 int curr = boxes[box].first, next;
00249 while (curr != -1) {
00250 next = data[curr].next;
00251 bubble_down(curr);
00252 curr = next;
00253 }
00254 }
00255
00256 void relocate_last(int index) {
00257 if (index != (int)data.size() - 1) {
00258 data[index] = data.back();
00259 if (data[index].prev != -1) {
00260 data[data[index].prev].next = index;
00261 } else {
00262 boxes[data[index].box].first = index;
00263 }
00264 if (data[index].next != -1) {
00265 data[data[index].next].prev = index;
00266 }
00267 iim[data[index].item] = index;
00268 }
00269 data.pop_back();
00270 }
00271
00272 public:
00273
00279 void push(const Item &i, const Prio &p) {
00280 int n = data.size();
00281 iim.set(i, n);
00282 data.push_back(RadixItem(i, p));
00283 while (lower(boxes.size() - 1, p)) {
00284 extend();
00285 }
00286 int box = findDown(boxes.size() - 1, p);
00287 insert(box, n);
00288 }
00289
00294 Item top() const {
00295 const_cast<RadixHeap<Item, ItemIntMap>*>(this)->moveDown();
00296 return data[boxes[0].first].item;
00297 }
00298
00303 Prio prio() const {
00304 const_cast<RadixHeap<Item, ItemIntMap>*>(this)->moveDown();
00305 return data[boxes[0].first].prio;
00306 }
00307
00312 void pop() {
00313 moveDown();
00314 int index = boxes[0].first;
00315 iim[data[index].item] = POST_HEAP;
00316 remove(index);
00317 relocate_last(index);
00318 }
00319
00325 void erase(const Item &i) {
00326 int index = iim[i];
00327 iim[i] = POST_HEAP;
00328 remove(index);
00329 relocate_last(index);
00330 }
00331
00337 Prio operator[](const Item &i) const {
00338 int idx = iim[i];
00339 return data[idx].prio;
00340 }
00341
00350 void set(const Item &i, const Prio &p) {
00351 int idx = iim[i];
00352 if( idx < 0 ) {
00353 push(i, p);
00354 }
00355 else if( p >= data[idx].prio ) {
00356 data[idx].prio = p;
00357 bubble_up(idx);
00358 } else {
00359 data[idx].prio = p;
00360 bubble_down(idx);
00361 }
00362 }
00363
00364
00372 void decrease(const Item &i, const Prio &p) {
00373 int idx = iim[i];
00374 data[idx].prio = p;
00375 bubble_down(idx);
00376 }
00377
00385 void increase(const Item &i, const Prio &p) {
00386 int idx = iim[i];
00387 data[idx].prio = p;
00388 bubble_up(idx);
00389 }
00390
00399 state_enum state(const Item &i) const {
00400 int s = iim[i];
00401 if( s >= 0 ) s = 0;
00402 return state_enum(s);
00403 }
00404
00405 };
00406
00407
00409
00410 }
00411
00412 #endif // LEMON_RADIX_HEAP_H