-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathMinHeap.h
390 lines (340 loc) · 11.5 KB
/
MinHeap.h
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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
#pragma once
#include <CppCore/Root.h>
#include <CppCore/Containers/Util/Comparer.h>
namespace CppCore
{
/// <summary>
/// Fixed Size MinHeap.
/// See nested classes ST and MT.
/// </summary>
class MinHeap
{
private:
INLINE MinHeap() { }
public:
/// <summary>
/// MinHeap for Single Thread Access
/// </summary>
template <typename T, size_t SIZE, typename KEY=T>
class ST
{
protected:
T mHeap[SIZE];
size_t mLength;
INLINE static size_t left(const size_t i) { return (2 * i + 1); }
INLINE static size_t right(const size_t i) { return (2 * i + 2); }
INLINE static size_t parent(const size_t i) { return ((i - 1) / 2); }
public:
/// <summary>
/// Complexity: (1)
/// Root is stored at index 0, then breadth-first.
/// </summary>
INLINE T& operator[](size_t index) { return mHeap[index]; }
protected:
/// <summary>
/// C++ Iterator (BACKWARDS)
/// </summary>
class Iterator
{
protected:
size_t mIdx;
ST& mHeap;
public:
INLINE Iterator(size_t idx, ST& heap) : mIdx(idx), mHeap(heap) { }
INLINE T& operator*() { return mHeap[mIdx]; }
INLINE Iterator& operator++() { mIdx--; return *this; }
INLINE bool operator!=(const Iterator& end) const { return mIdx != numeric_limits<size_t>::max(); }
};
/// <summary>
/// Helper Function
/// </summary>
INLINE void swap(const size_t idx1, const size_t idx2)
{
T temp = mHeap[idx1];
mHeap[idx1] = mHeap[idx2];
mHeap[idx2] = temp;
}
public:
/// <summary>
/// Constructor
/// </summary>
INLINE ST() : mLength(0) { }
INLINE Iterator begin() { return Iterator(mLength - 1, *this); }
INLINE Iterator end() { return Iterator(0, *this); }
/// <summary>
/// Complexity: O(1)
/// </summary>
INLINE size_t size() const { return SIZE; }
/// <summary>
/// Complexity: O(1)
/// </summary>
INLINE size_t length() const { return mLength; }
/// <summary>
/// Complexity: O(1)
/// </summary>
INLINE void clear()
{
mLength = 0;
}
//////////////////////////////////////////////////////////////////////
/// <summary>
/// Moves heap entry with changed key upwards until in right spot again.
/// No bound check on idx.
/// </summary>
template<typename COMPARER = Comparer<T, T>>
INLINE void fixOrderAtUp(size_t idx)
{
// move node up until in place
while (idx > 0)
{
// idx of parent
const size_t p = parent(idx);
// move up as long as smaller
if (COMPARER::less(mHeap[idx], mHeap[p]))
{
swap(idx, p); // swap them
idx = p; // loop again with parent
}
else
return;
}
}
/// <summary>
/// Moves heap entry with changed key downwards until in right spot again.
/// No bound check on idx.
/// </summary>
template<typename COMPARER = Comparer<T, T>>
INLINE void fixOrderAtDown(size_t idx, const size_t len)
{
// move node down until in place
while (true)
{
// left and right child
const size_t lc = left(idx);
const size_t rc = right(idx);
// min of this and both children
size_t min = idx;
// left is smaller
if (lc < len && COMPARER::less(mHeap[lc], mHeap[min]))
min = lc;
// right is (even) smaller
if (rc < len && COMPARER::less(mHeap[rc], mHeap[min]))
min = rc;
// left or right was smaller
if (min != idx)
{
swap(idx, min);
idx = min;
}
else
return;
}
}
/// <summary>
/// Moves heap entry with changed key until in right spot again.
/// No bound check on idx.
/// If you know the direction, call the subfunc directly!
/// </summary>
template<typename COMPARER = Comparer<T, T>>
INLINE void fixOrderAt(size_t idx)
{
fixOrderAtUp<COMPARER>(idx); // move up if necessary
fixOrderAtDown<COMPARER>(idx, mLength); // move down if necessary
}
//////////////////////////////////////////////////////////////////////
/// <summary>
/// Complexity: O(log(n))
/// </summary>
template<typename COMPARER = Comparer<T, T>>
INLINE bool removeAt(T& item, size_t idx)
{
size_t len = mLength;
if (idx < len)
{
len--; // decrement length
mLength = len; // write back new length
item = mHeap[idx]; // set node at idx as return value
mHeap[idx] = mHeap[len]; // put last at removed position
fixOrderAtDown<COMPARER>(idx, len); // move down until in place again
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////
/// <summary>
/// Complexity: O(log(n))
/// </summary>
template<typename COMPARER = Comparer<T, T>>
INLINE bool push(const T& item)
{
size_t idx = mLength;
if (idx < SIZE)
{
mHeap[idx] = item; // add item at the end
mLength = idx + 1; // write back incremented length
fixOrderAtUp<COMPARER>(idx); // move node up until in place
return true;
}
return false;
}
/// <summary>
/// Complexity: O(log(n))
/// </summary>
template<typename COMPARER = Comparer<T, T>>
INLINE bool pop(T& item)
{
return removeAt<COMPARER>(item, 0);
}
/// <summary>
/// Complexity: O(1)
/// </summary>
INLINE bool peek(T& item)
{
if (mLength > 0)
{
item = mHeap[0];
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////
/// <summary>
/// Complexity: O(n)
/// </summary>
template<typename COMPARER = Comparer<T, KEY>>
INLINE bool find(const KEY& key, size_t& idx)
{
const size_t LEN = mLength;
for (idx = 0; idx < LEN; idx++)
if (COMPARER::equal(mHeap[idx], key))
return true;
return false;
}
//////////////////////////////////////////////////////////////////////
/// <summary>
/// Complexity: O(n+log(n))
/// </summary>
template<typename CMPKEY = Comparer<T, KEY>, typename CMPOBJ = Comparer<T, T>>
INLINE bool removeOne(const KEY& key, T& item)
{
size_t idx = 0;
if (find<CMPKEY>(key, idx))
return removeAt<CMPOBJ>(item, idx);
return false;
}
/// <summary>
/// Complexity: O(k*(n+log(n))) , k=found matches
/// </summary>
template<typename CMPKEY = Comparer<T, KEY>, typename CMPOBJ = Comparer<T, T>>
INLINE size_t removeAll(const KEY& key)
{
T temp;
size_t idx = 0;
size_t counter = 0;
// find all occurences
while (find<CMPKEY>(key, idx))
{
// remove it
if (removeAt<CMPOBJ>(temp, idx))
counter++;
// must search from root again
idx = 0;
}
return counter;
}
/// <summary>
/// For debugging purposes only.
/// </summary>
template<typename COMPARER = Comparer<T, T>>
INLINE bool validate(size_t* stack, size_t idx = 0)
{
const size_t LEN = mLength;
if (idx < LEN)
{
size_t stidx = 0; // index on stack
stack[++stidx] = idx; // push first index
do
{
// pop next index/node
idx = stack[stidx--];
// get indices of children
const size_t lc = left(idx);
const size_t rc = right(idx);
// test left child
if (lc < LEN)
{
// left child must not be smaller
if (COMPARER::less(mHeap[lc], mHeap[idx]))
return false;
// if ok add to ones to evaluate next
else
stack[++stidx] = lc;
}
// test right child
if (rc < LEN)
{
// right child must not be smaller
if (COMPARER::less(mHeap[rc], mHeap[idx]))
return false;
// if ok add to ones to evaluate next
else
stack[++stidx] = rc;
}
} while (stidx);
// all good
return true;
}
// index out ouf bound
else
return false;
}
};
#ifndef CPPCORE_NO_THREADING
/// <summary>
/// MinHeap for Multi Thread Access with internal Locking
/// </summary>
template <typename T, size_t SIZE, typename KEY=T>
class MT : ST<T, SIZE, KEY>
{
protected:
CPPCORE_MUTEX_TYPE mLock;
public:
INLINE MT() : ST<T, SIZE, KEY>() { }
INLINE size_t size() { return SIZE; }
template<typename COMPARER = Comparer<T, T>>
INLINE bool push(const T& item)
{
CPPCORE_MUTEX_LOCK(mLock);
bool ret = ST<T, SIZE, KEY>::template push<COMPARER>(item);
CPPCORE_MUTEX_UNLOCK(mLock);
return ret;
}
template<typename COMPARER = Comparer<T, T>>
INLINE bool pop(T& item)
{
CPPCORE_MUTEX_LOCK(mLock);
bool ret = ST<T, SIZE, KEY>::template pop<COMPARER>(item);
CPPCORE_MUTEX_UNLOCK(mLock);
return ret;
}
INLINE void clear()
{
CPPCORE_MUTEX_LOCK(mLock);
ST<T, SIZE, KEY>::clear();
CPPCORE_MUTEX_UNLOCK(mLock);
}
/// <summary>
/// BEWARE: You must consider the returned value already outdated/invalid.
/// This is for e.g. monitoring usage only.
/// </summary>
INLINE size_t length()
{
CPPCORE_MUTEX_LOCK(mLock);
size_t ret = ST<T, SIZE, KEY>::length();
CPPCORE_MUTEX_UNLOCK(mLock);
return ret;
}
};
#endif
};
}