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 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
|
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
#ifndef QTPFS_NODEHEAP_HDR
#define QTPFS_NODEHEAP_HDR
#include <limits>
#include <vector>
#include "PathDefines.hpp"
#define NODE_CMP_EQ(a, b) (a->operator==(b))
#define NODE_CMP_LT(a, b) (a->operator< (b))
#define NODE_CMP_LE(a, b) (a->operator<=(b))
#define NODE_CMP_GT(a, b) (a->operator> (b))
#define NODE_CMP_GE(a, b) (a->operator>=(b))
namespace QTPFS {
template<class TNode> class binary_heap {
public:
binary_heap() { clear(); }
binary_heap(size_t n) { reserve(n); }
~binary_heap() { clear(); }
// interface functions
void push(TNode n) {
#ifdef QTPFS_DEBUG_NODE_HEAP
check_heap_property(0);
#endif
assert(cur_idx < nodes.size());
// park new node at first free spot
nodes[cur_idx] = n;
nodes[cur_idx]->SetHeapIndex(cur_idx);
if (cur_idx == max_idx)
nodes.resize(nodes.size() * 2);
cur_idx += 1;
max_idx = nodes.size() - 1;
// move new node up if necessary
if (size() > 1)
inc_heap(cur_idx - 1);
#ifdef QTPFS_DEBUG_NODE_HEAP
check_heap_property(0);
#endif
}
void pop() {
#ifdef QTPFS_DEBUG_NODE_HEAP
check_heap_property(0);
#endif
assert(cur_idx <= max_idx);
// exchange root and last node
if (size() > 1)
swap_nodes(0, cur_idx - 1);
// former position of last node is now free
cur_idx -= 1;
assert(cur_idx <= max_idx);
// kill old root
nodes[cur_idx]->SetHeapIndex(-1u);
nodes[cur_idx] = NULL;
// move new root (former last node) down if necessary
if (size() > 1)
dec_heap(0);
#ifdef QTPFS_DEBUG_NODE_HEAP
check_heap_property(0);
#endif
}
TNode top() {
assert(!empty());
return nodes[0];
}
// utility functions
bool empty() const { return (size() == 0); }
// bool full() const { return (size() >= capacity()); }
size_t size() const { return (cur_idx); }
size_t capacity() const { return (max_idx + 1); }
void clear() {
nodes.clear();
cur_idx = 0;
max_idx = -1u;
}
void reserve(size_t size) {
nodes.clear();
nodes.resize(size, NULL);
cur_idx = 0;
max_idx = size - 1;
}
// acts like reserve(), but without re-allocating
void reset() {
assert(!nodes.empty());
cur_idx = 0;
max_idx = nodes.size() - 1;
}
void resort(TNode n) {
assert(n != NULL);
assert(valid_idx(n->GetHeapIndex()));
const size_t n_idx = n->GetHeapIndex();
const size_t n_rel = is_sorted(n_idx);
// bail if <n> does not actually break the heap-property
if (n_rel == 0) {
return;
} else {
if (n_rel == 1) {
// parent of <n> is larger, move <n> further up
inc_heap(n_idx);
} else {
// parent of <n> is smaller, move <n> further down
dec_heap(n_idx);
}
}
#ifdef QTPFS_DEBUG_NODE_HEAP
check_heap_property(0);
#endif
}
void check_heap_property(size_t idx) const {
#ifdef QTPFS_DEBUG_NODE_HEAP
if (valid_idx(idx)) {
assert(is_sorted(idx) == 0);
check_heap_property(l_child_idx(idx));
check_heap_property(r_child_idx(idx));
}
#endif
}
#ifdef QTPFS_DEBUG_PRINT_NODE_HEAP
void debug_print(size_t idx, size_t calls, const std::string& tabs) const {
if (calls == 0)
return;
if (valid_idx(idx)) {
debug_print(r_child_idx(idx), calls - 1, tabs + "\t");
printf("%shi=%u :: hp=%.2f\n", tabs.c_str(), nodes[idx]->GetHeapIndex(), nodes[idx]->GetHeapPriority());
debug_print(l_child_idx(idx), calls - 1, tabs + "\t");
}
}
#endif
private:
size_t parent_idx(size_t n_idx) const { return ((n_idx - 1) >> 1); }
size_t l_child_idx(size_t n_idx) const { return ((n_idx << 1) + 1); }
size_t r_child_idx(size_t n_idx) const { return ((n_idx << 1) + 2); }
// tests if <idx> belongs to the tree built over [0, cur_idx)
bool valid_idx(size_t idx) const { return (idx < cur_idx); }
// test whether the node at <nidx> is in the right place
// parent must have smaller / equal value, children must
// have larger / equal value
//
size_t is_sorted(size_t n_idx) const {
const size_t p_idx = parent_idx(n_idx);
const size_t l_c_idx = l_child_idx(n_idx);
const size_t r_c_idx = r_child_idx(n_idx);
if (n_idx != 0) {
// check if parent > node
assert(valid_idx(p_idx));
assert(nodes[p_idx] != NULL);
assert(nodes[n_idx] != NULL);
if (NODE_CMP_GT(nodes[p_idx], nodes[n_idx])) {
return 1;
}
}
if (valid_idx(l_c_idx)) {
// check if l_child < node
assert(nodes[l_c_idx] != NULL);
assert(nodes[ n_idx] != NULL);
if (NODE_CMP_LT(nodes[l_c_idx], nodes[n_idx])) {
return 2;
}
}
if (valid_idx(r_c_idx)) {
// check if r_child < node
assert(nodes[r_c_idx] != NULL);
assert(nodes[ n_idx] != NULL);
if (NODE_CMP_LT(nodes[r_c_idx], nodes[n_idx])) {
return 2;
}
}
return 0;
}
void inc_heap(size_t c_idx) {
size_t p_idx = 0;
while (c_idx >= 1) {
p_idx = parent_idx(c_idx);
assert(valid_idx(p_idx));
assert(valid_idx(c_idx));
if (NODE_CMP_LE(nodes[p_idx], nodes[c_idx])) {
break;
}
swap_nodes(p_idx, c_idx);
// move up one level
c_idx = p_idx;
}
}
void dec_heap(size_t p_idx) {
size_t c_idx = -1u;
size_t l_c_idx = l_child_idx(p_idx);
size_t r_c_idx = r_child_idx(p_idx);
while (valid_idx(l_c_idx) || valid_idx(r_c_idx)) {
if (!valid_idx(r_c_idx)) {
// node only has a left child
c_idx = l_c_idx;
} else {
if (NODE_CMP_LE(nodes[l_c_idx], nodes[r_c_idx])) {
// left child is smaller or equal to right child
// according to the node total ordering, pick it
c_idx = l_c_idx;
} else {
// pick the right child
c_idx = r_c_idx;
}
}
if (NODE_CMP_LE(nodes[p_idx], nodes[c_idx])) {
// parent is smaller (according to the
// node total ordering) than the child
break;
}
swap_nodes(p_idx, c_idx);
p_idx = c_idx;
l_c_idx = l_child_idx(p_idx);
r_c_idx = r_child_idx(p_idx);
}
}
void swap_nodes(size_t idx1, size_t idx2) {
assert(idx1 != idx2);
assert(idx1 < cur_idx);
assert(idx2 < cur_idx);
TNode n1 = nodes[idx1];
TNode n2 = nodes[idx2];
assert(n1 != n2);
assert(n1->GetHeapIndex() == idx1);
assert(n2->GetHeapIndex() == idx2);
nodes[idx1] = n2;
nodes[idx2] = n1;
n2->SetHeapIndex(idx1);
n1->SetHeapIndex(idx2);
}
private:
std::vector<TNode> nodes;
size_t cur_idx; // index of first free (unused) slot
size_t max_idx; // index of last free (unused) slot
};
}
#endif
|