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