F´ Flight Software - C/C++ Documentation NASA-v1.6.0
A framework for building embedded system applications to NASA flight quality standards.
Loading...
Searching...
No Matches
MaxHeap.cpp
Go to the documentation of this file.
1// ======================================================================
2// \title MaxHeap.cpp
3// \author dinkel
4// \brief An implementation of a stable max heap data structure. Items
5// popped off the heap are guaranteed to be in order of decreasing
6// "value" (max removed first). Items of equal "value" will be
7// popped off in FIFO order. The performance of both push and pop
8// is O(log(n)).
9//
10// \copyright
11// Copyright 2009-2015, by the California Institute of Technology.
12// ALL RIGHTS RESERVED. United States Government Sponsorship
13// acknowledged.
14//
15// ======================================================================
16
18#include <FpConfig.hpp>
19#include "Fw/Types/Assert.hpp"
20#include <Fw/Logger/Logger.hpp>
21
22#include <new>
23#include <cstdio>
24
25// Macros for traversing the heap:
26#define LCHILD(x) (2 * x + 1)
27#define RCHILD(x) (2 * x + 2)
28#define PARENT(x) ((x - 1) / 2)
29
30namespace Os {
31
33 // Initialize the heap:
34 this->capacity = 0;
35 this->heap = nullptr;
36 this->size = 0;
37 this->order = 0;
38 }
39
41 delete [] this->heap;
42 this->heap = nullptr;
43 }
44
46 {
47 // The heap has already been created.. so delete
48 // it and try again.
49 if( nullptr != this->heap ) {
50 delete [] this->heap;
51 this->heap = nullptr;
52 }
53
54 this->heap = new(std::nothrow) Node[capacity];
55 if( nullptr == this->heap ) {
56 return false;
57 }
58 this->capacity = capacity;
59 return true;
60 }
61
63 // If the queue is full, return false:
64 if(this->isFull()) {
65 return false;
66 }
67
68 // Heap indexes:
69 NATIVE_UINT_TYPE parent;
70 NATIVE_UINT_TYPE index = this->size;
71
72 // Max loop bounds for bit flip protection:
73 NATIVE_UINT_TYPE maxIter = this->size+1;
74 NATIVE_UINT_TYPE maxCount = 0;
75
76 // Start at the bottom of the heap and work our ways
77 // upwards until we find a parent that has a value
78 // greater than ours.
79 while(index && maxCount < maxIter) {
80 // Get the parent index:
81 parent = PARENT(index);
82 // The parent index should ALWAYS be less than the
83 // current index. Let's verify that.
84 FW_ASSERT(parent < index, parent, index);
85 // If the current value is less than the parent,
86 // then the current index is in the correct place,
87 // so break out of the loop:
88 if(value <= this->heap[parent].value) {
89 break;
90 }
91 // Swap the parent and child:
92 this->heap[index] = this->heap[parent];
93 index = parent;
94 ++maxCount;
95 }
96
97 // Check for programming errors or bit flips:
98 FW_ASSERT(maxCount < maxIter, maxCount, maxIter);
99 FW_ASSERT(index <= this->size, index);
100
101 // Set the values of the new element:
102 this->heap[index].value = value;
103 this->heap[index].order = order;
104 this->heap[index].id = id;
105
106 ++this->size;
107 ++this->order;
108 return true;
109 }
110
112 // If there is nothing in the heap then
113 // return false:
114 if(this->isEmpty()) {
115 return false;
116 }
117
118 // Set the return values to the top (max) of
119 // the heap:
120 value = this->heap[0].value;
121 id = this->heap[0].id;
122
123 // Now place the last element on the heap in
124 // the root position, and resize the heap.
125 // This will put the smallest value in the
126 // heap on the top, violating the heap property.
127 NATIVE_UINT_TYPE index = this->size-1;
128 // Fw::Logger::logMsg("Putting on top: i: %u v: %d\n", index, this->heap[index].value);
129 this->heap[0]= this->heap[index];
130 --this->size;
131
132 // Now that the heap property is violated, we
133 // need to reorganize the heap to restore it's
134 // heapy-ness.
135 this->heapify();
136 return true;
137 }
138
139 // Is the heap full:
141 return (this->size == this->capacity);
142 }
143
144 // Is the heap empty:
146 return (this->size == 0);
147 }
148
149 // Get the current size of the heap:
151 return this->size;
152 }
153
154 // A non-recursive heapify method.
155 // Note: This method had an additional property, such that
156 // items pushed of the same priority will be popped in FIFO
157 // order.
158 void MaxHeap::heapify() {
159 NATIVE_UINT_TYPE index = 0;
160 NATIVE_UINT_TYPE left;
161 NATIVE_UINT_TYPE right;
162 NATIVE_UINT_TYPE largest;
163
164 // Max loop bounds for bit flip protection:
165 NATIVE_UINT_TYPE maxIter = this->size+1;
166 NATIVE_UINT_TYPE maxCount = 0;
167
168 while(index <= this->size && maxCount < maxIter) {
169 // Get the children indexes for this node:
170 left = LCHILD(index);
171 right = RCHILD(index);
172 FW_ASSERT(left > index, left, index);
173 FW_ASSERT(right > left, right, left);
174
175 // If the left node is bigger than the heap
176 // size, we have reached the end of the heap
177 // so we can stop:
178 if (left >= this->size) {
179 break;
180 }
181
182 // Initialize the largest node to the current
183 // node:
184 largest = index;
185
186 // Which one is larger, the current node or
187 // the left node?:
188 largest = this->max(left, largest);
189
190 // Make sure the right node exists before checking it:
191 if (right < this->size) {
192 // Which one is larger, the current largest
193 // node or the right node?
194 largest = this->max(right, largest);
195 }
196
197 // If the largest node is the current node
198 // then we are done heapifying:
199 if (largest == index)
200 {
201 break;
202 }
203
204 // Swap the largest node with the current node:
205 // Fw::Logger::logMsg("Swapping: i: %u v: %d with i: %u v: %d\n",
206 // index, this->heap[index].value,
207 // largest, this->heap[largest].value);
208 this->swap(index, largest);
209
210 // Set the new index to whichever child was larger:
211 index = largest;
212 }
213
214 // Check for programming errors or bit flips:
215 FW_ASSERT(maxCount < maxIter, maxCount, maxIter);
216 FW_ASSERT(index <= this->size, index);
217 }
218
219 // Return the maximum priority index between two nodes. If their
220 // priorities are equal, return the oldest to keep the heap stable
222 FW_ASSERT(a < this->size, a, this->size);
223 FW_ASSERT(b < this->size, b, this->size);
224
225 // Extract the priorities:
226 NATIVE_INT_TYPE aValue = this->heap[a].value;
227 NATIVE_INT_TYPE bValue = this->heap[b].value;
228
229 // If the priorities are equal, the "larger" one will be
230 // the "older" one as determined by order pushed on to the
231 // heap. Using this secondary ordering technique makes the
232 // heap stable (ie. FIFO for equal priority elements).
233 // Note: We check this first, because it is the most common
234 // case. Let's save as many ticks as we can...
235 if(aValue == bValue) {
236 NATIVE_UINT_TYPE aAge = this->order - this->heap[a].order;
237 NATIVE_UINT_TYPE bAge = this->order - this->heap[b].order;
238 if(aAge > bAge) {
239 return a;
240 }
241 return b;
242 }
243
244 // Which priority is larger?:
245 if( aValue > bValue ) {
246 return a;
247 }
248 // B is larger:
249 return b;
250 }
251
252 // Swap two nodes in the heap:
253 void MaxHeap::swap(NATIVE_UINT_TYPE a, NATIVE_UINT_TYPE b) {
254 FW_ASSERT(a < this->size, a, this->size);
255 FW_ASSERT(b < this->size, b, this->size);
256 Node temp = this->heap[a];
257 this->heap[a] = this->heap[b];
258 this->heap[b] = temp;
259 }
260
261 // Print heap, for debugging purposes only:
263 NATIVE_UINT_TYPE index = 0;
264 NATIVE_UINT_TYPE left;
265 NATIVE_UINT_TYPE right;
266 Fw::Logger::logMsg("Printing Heap of Size: %d\n", this->size);
267 while(index < this->size) {
268 left = LCHILD(index);
269 right = RCHILD(index);
270
271 if( left >= size && index == 0) {
272 Fw::Logger::logMsg("i: %u v: %d d: %u -> (NULL, NULL)\n",
273 index, this->heap[index].value, this->heap[index].id);
274 }
275 else if( right >= size && left < size ) {
276 Fw::Logger::logMsg("i: %u v: %d d: %u -> (i: %u v: %d d: %u, NULL)\n",
277 index, this->heap[index].value, this->heap[index].id,
278 left, this->heap[left].value, this->heap[left].id);
279 }
280 else if( right < size && left < size ) {
281 Fw::Logger::logMsg("i: %u v: %d d: %u -> (i: %u v: %d d: %u, i: %u v: %d d: %u)\n",
282 index, this->heap[index].value, this->heap[index].id,
283 left, this->heap[left].value,this->heap[left].id,
284 right, this->heap[right].value, this->heap[right].id);
285 }
286
287 ++index;
288 }
289 }
290}
#define FW_ASSERT(...)
Definition Assert.hpp:7
PlatformIntType NATIVE_INT_TYPE
Definition BasicTypes.h:51
PlatformUIntType NATIVE_UINT_TYPE
Definition BasicTypes.h:52
C++-compatible configuration header for fprime configuration.
#define LCHILD(x)
Definition MaxHeap.cpp:26
#define PARENT(x)
Definition MaxHeap.cpp:28
#define RCHILD(x)
Definition MaxHeap.cpp:27
static void logMsg(const char *fmt, POINTER_CAST a0=0, POINTER_CAST a1=0, POINTER_CAST a2=0, POINTER_CAST a3=0, POINTER_CAST a4=0, POINTER_CAST a5=0, POINTER_CAST a6=0, POINTER_CAST a7=0, POINTER_CAST a8=0, POINTER_CAST a9=0)
Definition Logger.cpp:18
bool isFull()
Is the heap full?
Definition MaxHeap.cpp:140
~MaxHeap()
MaxHeap deconstructor.
Definition MaxHeap.cpp:40
bool push(NATIVE_INT_TYPE value, NATIVE_UINT_TYPE id)
Push an item onto the heap.
Definition MaxHeap.cpp:62
MaxHeap()
MaxHeap constructor.
Definition MaxHeap.cpp:32
bool create(NATIVE_UINT_TYPE capacity)
MaxHeap creation.
Definition MaxHeap.cpp:45
void print()
Print the contents of the heap to stdout.
Definition MaxHeap.cpp:262
bool pop(NATIVE_INT_TYPE &value, NATIVE_UINT_TYPE &id)
Pop an item from the heap.
Definition MaxHeap.cpp:111
bool isEmpty()
Is the heap empty?
Definition MaxHeap.cpp:145
NATIVE_UINT_TYPE getSize()
Get the current number of elements on the heap.
Definition MaxHeap.cpp:150
Definition File.cpp:6