deba@1186: /* -*- C++ -*- deba@1186: * src/lemon/bin_heap.h - Part of LEMON, a generic C++ optimization library deba@1186: * deba@1186: * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@1186: * (Egervary Combinatorial Optimization Research Group, EGRES). deba@1186: * deba@1186: * Permission to use, modify and distribute this software is granted deba@1186: * provided that this copyright notice appears in all copies. For deba@1186: * precise terms see the accompanying LICENSE file. deba@1186: * deba@1186: * This software is provided "AS IS" with no warranty of any kind, deba@1186: * express or implied, and with no claim as to its suitability for any deba@1186: * purpose. deba@1186: * deba@1186: */ deba@1186: deba@1186: #ifndef LEMON_RADIX_HEAP_H deba@1186: #define LEMON_RADIX_HEAP_H deba@1186: deba@1186: ///\ingroup auxdat deba@1186: ///\file deba@1186: ///\brief Radix Heap implementation. deba@1186: ///\todo It should be documented. deba@1186: deba@1186: #include deba@1186: #include deba@1186: deba@1186: namespace lemon { deba@1186: deba@1186: /// \addtogroup auxdat deba@1186: /// @{ deba@1186: deba@1205: /// A Radix Heap implementation. deba@1186: deba@1186: ///\todo Please document... deba@1186: /// deba@1186: ///\sa BinHeap deba@1186: ///\sa Dijkstra deba@1186: deba@1186: class UnderFlowPriorityException : public RuntimeError { deba@1186: public: deba@1186: virtual const char* exceptionName() const { deba@1186: return "lemon::UnderFlowPriorityException"; deba@1186: } deba@1186: }; deba@1186: deba@1186: template deba@1186: class RadixHeap { deba@1186: deba@1186: public: deba@1186: typedef _Item Item; deba@1186: // FIXME: stl-ben nem ezt hivjak value_type -nak, hanem a kovetkezot... deba@1186: typedef int Prio; deba@1186: typedef _ItemIntMap ItemIntMap; deba@1186: deba@1186: /** deba@1186: * Each Item element have a state associated to it. It may be "in heap", deba@1186: * "pre heap" or "post heap". The later two are indifferent from the deba@1186: * heap's point of view, but may be useful to the user. deba@1186: * deba@1186: * The ItemIntMap _should_ be initialized in such way, that it maps deba@1186: * PRE_HEAP (-1) to any element to be put in the heap... deba@1186: */ deba@1186: ///\todo it is used nowhere deba@1186: /// deba@1186: enum state_enum { deba@1186: IN_HEAP = 0, deba@1186: PRE_HEAP = -1, deba@1186: POST_HEAP = -2 deba@1186: }; deba@1186: deba@1186: private: deba@1186: deba@1186: struct RadixItem { deba@1186: int prev, next, box; deba@1186: Item item; deba@1186: int prio; deba@1186: RadixItem(Item _item, int _prio) : item(_item), prio(_prio) {} deba@1186: }; deba@1186: deba@1186: struct RadixBox { deba@1186: int first; deba@1186: int min, size; deba@1186: RadixBox(int _min, int _size) : first(-1), min(_min), size(_size) {} deba@1186: }; deba@1186: deba@1186: std::vector data; deba@1186: std::vector boxes; deba@1186: deba@1186: ItemIntMap &iim; deba@1186: deba@1186: deba@1186: public: deba@1186: ///\e deba@1186: explicit RadixHeap(ItemIntMap &_iim) : iim(_iim) { deba@1186: boxes.push_back(RadixBox(0, 1)); deba@1186: boxes.push_back(RadixBox(1, 1)); deba@1186: } deba@1186: deba@1186: ///\e deba@1186: RadixHeap(ItemIntMap &_iim, int capacity) : iim(_iim) { deba@1186: boxes.push_back(RadixBox(0, 1)); deba@1186: boxes.push_back(RadixBox(1, 1)); deba@1186: while (upper(boxes.back(), capacity)) { deba@1186: extend(); deba@1186: } deba@1186: } deba@1186: deba@1186: ///\e deba@1186: int size() const { return data.size(); } deba@1186: ///\e deba@1186: bool empty() const { return data.empty(); } deba@1186: deba@1186: private: deba@1186: deba@1186: bool upper(int box, Prio prio) { deba@1186: return prio < boxes[box].min; deba@1186: } deba@1186: deba@1186: bool lower(int box, Prio prio) { deba@1186: return prio >= boxes[box].min + boxes[box].size; deba@1186: } deba@1186: deba@1186: /// \brief Remove item from the box list. deba@1186: void remove(int index) { deba@1186: if (data[index].prev >= 0) { deba@1186: data[data[index].prev].next = data[index].next; deba@1186: } else { deba@1186: boxes[data[index].box].first = data[index].next; deba@1186: } deba@1186: if (data[index].next >= 0) { deba@1186: data[data[index].next].prev = data[index].prev; deba@1186: } deba@1186: } deba@1186: deba@1186: /// \brief Insert item into the box list. deba@1186: void insert(int box, int index) { deba@1186: if (boxes[box].first == -1) { deba@1186: boxes[box].first = index; deba@1186: data[index].next = data[index].prev = -1; deba@1186: } else { deba@1186: data[index].next = boxes[box].first; deba@1186: data[boxes[box].first].prev = index; deba@1186: data[index].prev = -1; deba@1186: boxes[box].first = index; deba@1186: } deba@1186: data[index].box = box; deba@1186: } deba@1186: deba@1186: /// \brief Add a new box to the box list. deba@1186: void extend() { deba@1186: int min = boxes.back().min + boxes.back().size; deba@1186: int size = 2 * boxes.back().size; deba@1186: boxes.push_back(RadixBox(min, size)); deba@1186: } deba@1186: deba@1186: /// \brief Move an item up into the proper box. deba@1186: void bubble_up(int index) { deba@1205: if (!lower(data[index].box, data[index].prio)) return; deba@1186: remove(index); deba@1186: int box = findUp(data[index].box, data[index].prio); deba@1186: insert(box, index); deba@1186: } deba@1186: deba@1186: /// \brief Find up the proper box for the item with the given prio. deba@1186: int findUp(int start, int prio) { deba@1186: while (lower(start, prio)) { deba@1186: if (++start == (int)boxes.size()) { deba@1186: extend(); deba@1186: } deba@1186: } deba@1186: return start; deba@1186: } deba@1186: deba@1186: /// \brief Move an item down into the proper box. deba@1186: void bubble_down(int index) { deba@1186: if (!upper(data[index].box, data[index].prio)) return; deba@1186: remove(index); deba@1186: int box = findDown(data[index].box, data[index].prio); deba@1186: insert(box, index); deba@1186: } deba@1186: deba@1186: /// \brief Find up the proper box for the item with the given prio. deba@1186: int findDown(int start, int prio) { deba@1186: while (upper(start, prio)) { deba@1186: if (--start < 0) throw UnderFlowPriorityException(); deba@1186: } deba@1186: return start; deba@1186: } deba@1186: deba@1186: /// \brief Find the first not empty box. deba@1186: int findFirst() { deba@1186: int first = 0; deba@1186: while (boxes[first].first == -1) ++first; deba@1186: return first; deba@1186: } deba@1186: deba@1186: /// \brief Gives back the minimal prio of the box. deba@1186: int minValue(int box) { deba@1186: int min = data[boxes[box].first].prio; deba@1186: for (int k = boxes[box].first; k != -1; k = data[k].next) { deba@1186: if (data[k].prio < min) min = data[k].prio; deba@1186: } deba@1186: return min; deba@1186: } deba@1186: deba@1186: /// \brief Rearrange the items of the heap and makes the deba@1186: /// first box not empty. deba@1186: void moveDown() { deba@1186: // print(); printf("moveDown\n"); fflush(stdout); deba@1186: int box = findFirst(); deba@1186: if (box == 0) return; deba@1186: int min = minValue(box); deba@1186: for (int i = 0; i <= box; ++i) { deba@1186: boxes[i].min = min; deba@1186: min += boxes[i].size; deba@1186: } deba@1186: int curr = boxes[box].first, next; deba@1186: while (curr != -1) { deba@1186: next = data[curr].next; deba@1186: bubble_down(curr); deba@1186: curr = next; deba@1186: } deba@1186: } deba@1186: deba@1186: void relocate_last(int index) { deba@1186: if (index != (int)data.size() - 1) { deba@1186: data[index] = data.back(); deba@1186: if (data[index].prev != -1) { deba@1186: data[data[index].prev].next = index; deba@1186: } else { deba@1186: boxes[data[index].box].first = index; deba@1186: } deba@1186: if (data[index].next != -1) { deba@1186: data[data[index].next].prev = index; deba@1186: } deba@1186: iim[data[index].item] = index; deba@1186: } deba@1186: data.pop_back(); deba@1186: } deba@1186: deba@1186: public: deba@1186: deba@1186: ///\e deba@1186: void push(const Item &i, const Prio &p) { deba@1186: fflush(stdout); deba@1186: int n = data.size(); deba@1186: iim.set(i, n); deba@1186: data.push_back(RadixItem(i, p)); deba@1186: while (lower(boxes.size() - 1, p)) { deba@1186: extend(); deba@1186: } deba@1186: int box = findDown(boxes.size() - 1, p); deba@1186: insert(box, n); deba@1186: // printf("Push %d\n", p); deba@1186: //print(); deba@1186: } deba@1186: deba@1186: ///\e deba@1186: Item top() const { deba@1186: // print(); printf("top\n"); fflush(stdout); deba@1186: const_cast*>(this)->moveDown(); deba@1186: return data[boxes[0].first].item; deba@1186: // print(); printf("top_end\n"); fflush(stdout); deba@1186: } deba@1186: deba@1186: /// Returns the prio of the top element of the heap. deba@1186: Prio prio() const { deba@1186: // print(); printf("prio\n"); fflush(stdout); deba@1186: const_cast*>(this)->moveDown(); deba@1186: return data[boxes[0].first].prio; deba@1186: } deba@1186: deba@1186: ///\e deba@1186: void pop() { deba@1186: // print(); printf("pop\n"); fflush(stdout); deba@1186: moveDown(); deba@1186: int index = boxes[0].first; deba@1186: iim[data[index].item] = POST_HEAP; deba@1186: remove(index); deba@1186: relocate_last(index); deba@1186: // printf("Pop \n"); deba@1186: //print(); deba@1186: } deba@1186: deba@1186: ///\e deba@1186: void erase(const Item &i) { deba@1186: int index = iim[i]; deba@1186: iim[i] = POST_HEAP; deba@1186: remove(index); deba@1186: relocate_last(index); deba@1186: } deba@1186: deba@1186: ///\e deba@1186: Prio operator[](const Item &i) const { deba@1186: int idx = iim[i]; deba@1186: return data[idx].prio; deba@1186: } deba@1186: deba@1186: ///\e deba@1186: void set(const Item &i, const Prio &p) { deba@1186: int idx = iim[i]; deba@1186: if( idx < 0 ) { deba@1186: push(i, p); deba@1186: } deba@1186: else if( p >= data[idx].prio ) { deba@1186: data[idx].prio = p; deba@1186: bubble_up(idx); deba@1186: } else { deba@1186: data[idx].prio = p; deba@1186: bubble_down(idx); deba@1186: } deba@1186: } deba@1186: deba@1186: ///\e deba@1186: void decrease(const Item &i, const Prio &p) { deba@1186: // print(); printf("decrease\n"); fflush(stdout); deba@1186: int idx = iim[i]; deba@1186: data[idx].prio = p; deba@1186: bubble_down(idx); deba@1186: } deba@1186: deba@1186: ///\e deba@1186: void increase(const Item &i, const Prio &p) { deba@1186: int idx = iim[i]; deba@1186: data[idx].prio = p; deba@1186: bubble_up(idx); deba@1186: } deba@1186: deba@1186: ///\e deba@1186: state_enum state(const Item &i) const { deba@1186: int s = iim[i]; deba@1186: if( s >= 0 ) s = 0; deba@1186: return state_enum(s); deba@1186: } deba@1186: deba@1205: // void print() const { deba@1205: // for (int i = 0; i < boxes.size(); ++i) { deba@1205: // printf("(%d, %d) ", boxes[i].min, boxes[i].size); deba@1205: // for (int k = boxes[i].first; k != -1; k = data[k].next) { deba@1205: // printf("%d ", data[k].prio); deba@1205: // } deba@1205: // printf("\n"); deba@1205: // } deba@1205: // fflush(stdout); deba@1205: // } deba@1186: deba@1186: }; // class RadixHeap deba@1186: deba@1186: deba@1186: ///@} deba@1186: deba@1186: } // namespace lemon deba@1186: deba@1186: #endif // LEMON_RADIX_HEAP_H