F´ Flight Software - C/C++ Documentation NASA-v1.6.0
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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