Files
@ r14651:4390ae2296be
Branch filter:
Location: cpp/openttd-patchpack/source/src/misc/binaryheap.hpp
r14651:4390ae2296be
5.7 KiB
text/x-c++hdr
(svn r19240) -Codechange: Unify HeapifyUp code (skidd13)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | /* $Id$ */
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file binaryheap.hpp Binary heap implementation. */
#ifndef BINARYHEAP_HPP
#define BINARYHEAP_HPP
/**
* 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) T*[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-than' operator '<' - used for comparing items before moving
*
*/
template <class T>
class CBinaryHeapT {
private:
uint m_size; ///< Number of items in the heap
uint m_max_size; ///< Maximum number of items the heap can hold
T **m_items; ///< The heap item pointers
public:
explicit CBinaryHeapT(uint max_items)
: m_size(0)
, m_max_size(max_items)
{
m_items = MallocT<T*>(max_items + 1);
}
~CBinaryHeapT()
{
Clear();
free(m_items);
m_items = NULL;
}
protected:
/** Heapify (move gap) down */
FORCEINLINE uint HeapifyDown(uint gap, T *item)
{
assert(gap != 0);
uint child = gap * 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] < *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;
}
return gap;
}
public:
/** Return the number of items stored in the priority queue.
* @return number of items in the queue */
FORCEINLINE uint 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 T& GetHead()
{
assert(!IsEmpty());
return *m_items[1];
}
FORCEINLINE T *End()
{
return m_items[1 + m_size];
}
/** Insert new item into the priority queue, maintaining heap order.
* @return false if the queue is full. */
FORCEINLINE void Push(T& new_item)
{
if (IsFull()) {
m_max_size *= 2;
m_items = ReallocT<T*>(m_items, m_max_size + 1);
}
/* make place for new item */
uint gap = ++m_size;
/* Heapify up */
while (gap > 1) {
/* compare [gap] with its parent */
uint parent = gap / 2;
if (new_item < *m_items[parent]) {
m_items[gap] = m_items[parent];
gap = parent;
} else {
/* we don't need to continue upstairs */
break;
}
}
m_items[gap] = &new_item;
CheckConsistency();
}
/** Remove and return the smallest item from the priority queue. */
FORCEINLINE T& PopHead()
{
T& ret = GetHead();
RemoveHead();
return ret;
}
/** Remove the smallest item from the priority queue. */
FORCEINLINE void RemoveHead()
{
assert(!IsEmpty());
m_size--;
/* at index 1 we have a gap now */
T *last = End();
uint gap = HeapifyDown(1, last);
/* move last item to the proper place */
if (!IsEmpty()) m_items[gap] = last;
CheckConsistency();
}
/** Remove item specified by index */
FORCEINLINE void RemoveByIdx(uint idx)
{
/* at position idx we have a gap now */
uint gap = idx;
if (idx < m_size) {
assert(idx >= 1);
m_size--;
T *last = End();
/* 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 */
uint 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;
}
}
gap = HeapifyDown(gap, last);
/* move last item to the proper place */
if (!IsEmpty()) m_items[gap] = last;
} else {
assert(idx == m_size);
m_size--;
}
CheckConsistency();
}
/** return index of the item that matches (using &item1 == &item2) the given item. */
FORCEINLINE uint FindLinear(const T& item) const
{
if (IsEmpty()) return 0;
for (T **ppI = m_items + 1, **ppLast = ppI + m_size; ppI <= ppLast; ppI++) {
if (*ppI == &item) {
return ppI - m_items;
}
}
return 0;
}
/** Make the priority queue empty.
* All remaining items will remain untouched. */
FORCEINLINE void Clear() {m_size = 0;}
/** verifies the heap consistency (added during first YAPF debug phase) */
FORCEINLINE void CheckConsistency()
{
/* enable it if you suspect binary heap doesn't work well */
#if 0
for (uint child = 2; child <= m_size; child++) {
uint parent = child / 2;
assert(!(*m_items[child] < *m_items[parent]));
}
#endif
}
};
#endif /* BINARYHEAP_HPP */
|