KUDr@3900: /* $Id$ */ KUDr@3900: KUDr@3900: #ifndef BINARYHEAP_HPP KUDr@3900: #define BINARYHEAP_HPP KUDr@3900: KUDr@3900: //void* operator new (size_t size, void* p) {return p;} KUDr@3900: #if defined(_MSC_VER) && (_MSC_VER >= 1400) KUDr@3900: //void operator delete (void* p, void* p2) {} KUDr@3900: #endif KUDr@3900: KUDr@3900: KUDr@3900: /** rubidium@4549: * Binary Heap as C++ template. rubidium@4549: * rubidium@4549: * For information about Binary Heap algotithm, rubidium@4549: * see: http://www.policyalmanac.org/games/binaryHeaps.htm rubidium@4549: * rubidium@4549: * Implementation specific notes: rubidium@4549: * rubidium@4549: * 1) It allocates space for item pointers (array). Items are allocated elsewhere. rubidium@4549: * rubidium@4549: * 2) ItemPtr [0] is never used. Total array size is max_items + 1, because we rubidium@4549: * use indices 1..max_items instead of zero based C indexing. rubidium@4549: * rubidium@4549: * 3) Item of the binary heap should support these public members: rubidium@4549: * - 'lower-then' operator '<' - used for comparing items before moving rubidium@4549: * rubidium@4549: */ KUDr@3900: KUDr@3900: template KUDr@3900: class CBinaryHeapT { KUDr@3900: public: KUDr@3900: typedef Titem_ *ItemPtr; KUDr@3900: private: KUDr@3900: int m_size; ///< Number of items in the heap KUDr@3900: int m_max_size; ///< Maximum number of items the heap can hold KUDr@3900: ItemPtr* m_items; ///< The heap item pointers KUDr@3900: KUDr@3900: public: KUDr@3900: explicit CBinaryHeapT(int max_items = 102400) KUDr@3900: : m_size(0) KUDr@3900: , m_max_size(max_items) KUDr@3900: { KUDr@3900: m_items = new ItemPtr[max_items + 1]; KUDr@3900: } KUDr@3900: KUDr@3900: ~CBinaryHeapT() KUDr@3900: { KUDr@3900: Clear(); KUDr@3900: delete [] m_items; KUDr@3900: m_items = NULL; KUDr@3900: } KUDr@3900: KUDr@3900: public: KUDr@3900: /** Return the number of items stored in the priority queue. rubidium@4549: * @return number of items in the queue */ KUDr@3900: FORCEINLINE int Size() const {return m_size;}; KUDr@3900: KUDr@3900: /** Test if the priority queue is empty. rubidium@4549: * @return true if empty */ KUDr@3900: FORCEINLINE bool IsEmpty() const {return (m_size == 0);}; KUDr@3900: KUDr@3900: /** Test if the priority queue is full. rubidium@4549: * @return true if full. */ KUDr@3900: FORCEINLINE bool IsFull() const {return (m_size >= m_max_size);}; KUDr@3900: KUDr@3900: /** Find the smallest item in the priority queue. rubidium@4549: * Return the smallest item, or throw assert if empty. */ KUDr@3900: FORCEINLINE Titem_& GetHead() {assert(!IsEmpty()); return *m_items[1];} KUDr@3900: KUDr@3900: /** Insert new item into the priority queue, maintaining heap order. rubidium@4549: * @return false if the queue is full. */ KUDr@3900: bool Push(Titem_& new_item); KUDr@3900: KUDr@3900: /** Remove and return the smallest item from the priority queue. */ KUDr@3900: FORCEINLINE Titem_& PopHead() {Titem_& ret = GetHead(); RemoveHead(); return ret;}; KUDr@3900: KUDr@3900: /** Remove the smallest item from the priority queue. */ KUDr@3900: void RemoveHead(); KUDr@3900: KUDr@3900: /** Remove item specified by index */ KUDr@3900: void RemoveByIdx(int idx); KUDr@3900: KUDr@3900: /** return index of the item that matches (using &item1 == &item2) the given item. */ KUDr@3900: int FindLinear(const Titem_& item) const; KUDr@3900: KUDr@3900: /** Make the priority queue empty. rubidium@4549: * All remaining items will remain untouched. */ KUDr@3900: void Clear() {m_size = 0;}; KUDr@3900: KUDr@3900: /** verifies the heap consistency (added during first YAPF debug phase) */ KUDr@3900: void CheckConsistency(); KUDr@3900: }; KUDr@3900: KUDr@3900: KUDr@3900: template KUDr@3900: FORCEINLINE bool CBinaryHeapT::Push(Titem_& new_item) KUDr@3900: { KUDr@3900: if (IsFull()) return false; KUDr@3900: KUDr@3900: // make place for new item KUDr@3900: int gap = ++m_size; KUDr@3900: // Heapify up KUDr@3900: for (int parent = gap / 2; (parent > 0) && (new_item < *m_items[parent]); gap = parent, parent /= 2) KUDr@3900: m_items[gap] = m_items[parent]; KUDr@3900: m_items[gap] = &new_item; KUDr@3900: CheckConsistency(); KUDr@3900: return true; KUDr@3900: } KUDr@3900: KUDr@3900: template KUDr@3900: FORCEINLINE void CBinaryHeapT::RemoveHead() KUDr@3900: { KUDr@3900: assert(!IsEmpty()); KUDr@3900: KUDr@3900: // at index 1 we have a gap now KUDr@3900: int gap = 1; KUDr@3900: KUDr@3900: // Heapify down: KUDr@3900: // last item becomes a candidate for the head. Call it new_item. KUDr@3900: Titem_& new_item = *m_items[m_size--]; KUDr@3900: KUDr@3900: // now we must maintain relation between parent and its children: KUDr@3900: // parent <= any child KUDr@3900: // from head down to the tail KUDr@3900: int child = 2; // first child is at [parent * 2] KUDr@3900: KUDr@3900: // while children are valid KUDr@3900: while (child <= m_size) { KUDr@3900: // choose the smaller child KUDr@3900: if (child < m_size && *m_items[child + 1] < *m_items[child]) KUDr@3900: child++; KUDr@3900: // is it smaller than our parent? KUDr@3900: if (!(*m_items[child] < new_item)) { KUDr@3900: // the smaller child is still bigger or same as parent => we are done KUDr@3900: break; KUDr@3900: } KUDr@3900: // if smaller child is smaller than parent, it will become new parent KUDr@3900: m_items[gap] = m_items[child]; KUDr@3900: gap = child; KUDr@3900: // where do we have our new children? KUDr@3900: child = gap * 2; KUDr@3900: } KUDr@3900: // move last item to the proper place rubidium@4434: if (m_size > 0) m_items[gap] = &new_item; KUDr@3900: CheckConsistency(); KUDr@3900: } KUDr@3900: KUDr@3900: template KUDr@3900: inline void CBinaryHeapT::RemoveByIdx(int idx) KUDr@3900: { KUDr@3900: // at position idx we have a gap now KUDr@3900: int gap = idx; KUDr@3900: Titem_& last = *m_items[m_size]; KUDr@3900: if (idx < m_size) { KUDr@3900: assert(idx >= 1); KUDr@3900: m_size--; KUDr@3900: // and the candidate item for fixing this gap is our last item 'last' KUDr@3900: // Move gap / last item up: KUDr@3900: while (gap > 1) KUDr@3900: { KUDr@3900: // compare [gap] with its parent KUDr@3900: int parent = gap / 2; KUDr@3900: if (last < *m_items[parent]) { KUDr@3900: m_items[gap] = m_items[parent]; KUDr@3900: gap = parent; KUDr@3900: } else { KUDr@3900: // we don't need to continue upstairs KUDr@3900: break; KUDr@3900: } KUDr@3900: } KUDr@3900: KUDr@3900: // Heapify (move gap) down: KUDr@3900: while (true) { KUDr@3900: // where we do have our children? KUDr@3900: int child = gap * 2; // first child is at [parent * 2] KUDr@3900: if (child > m_size) break; KUDr@3900: // choose the smaller child KUDr@3900: if (child < m_size && *m_items[child + 1] < *m_items[child]) KUDr@3900: child++; KUDr@3900: // is it smaller than our parent? KUDr@3900: if (!(*m_items[child] < last)) { KUDr@3900: // the smaller child is still bigger or same as parent => we are done KUDr@3900: break; KUDr@3900: } KUDr@3900: // if smaller child is smaller than parent, it will become new parent KUDr@3900: m_items[gap] = m_items[child]; KUDr@3900: gap = child; KUDr@3900: } KUDr@3900: // move parent to the proper place KUDr@3900: if (m_size > 0) m_items[gap] = &last; KUDr@3900: } KUDr@3900: else { KUDr@3900: assert(idx == m_size); KUDr@3900: m_size--; KUDr@3900: } KUDr@3900: CheckConsistency(); KUDr@3900: } KUDr@3900: KUDr@3900: template KUDr@3900: inline int CBinaryHeapT::FindLinear(const Titem_& item) const KUDr@3900: { KUDr@3900: if (IsEmpty()) return 0; KUDr@3900: for (ItemPtr *ppI = m_items + 1, *ppLast = ppI + m_size; ppI <= ppLast; ppI++) { KUDr@3900: if (*ppI == &item) { KUDr@3900: return ppI - m_items; KUDr@3900: } KUDr@3900: } KUDr@3900: return 0; KUDr@3900: } KUDr@3900: KUDr@3900: template KUDr@3900: FORCEINLINE void CBinaryHeapT::CheckConsistency() KUDr@3900: { KUDr@3900: // enable it if you suspect binary heap doesn't work well KUDr@3900: #if 0 KUDr@3900: for (int child = 2; child <= m_size; child++) { KUDr@3900: int parent = child / 2; KUDr@3900: assert(!(m_items[child] < m_items[parent])); KUDr@3900: } KUDr@3900: #endif KUDr@3900: } KUDr@3900: KUDr@3900: KUDr@3900: #endif /* BINARYHEAP_HPP */