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 "Fw/Types/BasicTypes.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 
30 namespace 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:
262  void MaxHeap::print() {
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 }
Os
Definition: File.cpp:7
Os::MaxHeap::push
bool push(NATIVE_INT_TYPE value, NATIVE_UINT_TYPE id)
Push an item onto the heap.
Definition: MaxHeap.cpp:62
Os::MaxHeap::create
bool create(NATIVE_UINT_TYPE capacity)
MaxHeap creation.
Definition: MaxHeap.cpp:45
Os::MaxHeap::isEmpty
bool isEmpty()
Is the heap empty?
Definition: MaxHeap.cpp:145
Os::MaxHeap::getSize
NATIVE_UINT_TYPE getSize()
Get the current number of elements on the heap.
Definition: MaxHeap.cpp:150
Assert.hpp
LCHILD
#define LCHILD(x)
Definition: MaxHeap.cpp:26
Os::MaxHeap::~MaxHeap
~MaxHeap()
MaxHeap deconstructor.
Definition: MaxHeap.cpp:40
PARENT
#define PARENT(x)
Definition: MaxHeap.cpp:28
NATIVE_UINT_TYPE
unsigned int NATIVE_UINT_TYPE
native unsigned integer type declaration
Definition: BasicTypes.hpp:30
Os::MaxHeap::print
void print()
Print the contents of the heap to stdout.
Definition: MaxHeap.cpp:262
FW_ASSERT
#define FW_ASSERT(...)
Definition: Assert.hpp:8
Os::MaxHeap::isFull
bool isFull()
Is the heap full?
Definition: MaxHeap.cpp:140
Fw::Logger::logMsg
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
MaxHeap.hpp
BasicTypes.hpp
Declares ISF basic types.
NATIVE_INT_TYPE
int NATIVE_INT_TYPE
native integer type declaration
Definition: BasicTypes.hpp:29
RCHILD
#define RCHILD(x)
Definition: MaxHeap.cpp:27
Logger.hpp
Os::MaxHeap::pop
bool pop(NATIVE_INT_TYPE &value, NATIVE_UINT_TYPE &id)
Pop an item from the heap.
Definition: MaxHeap.cpp:111
Os::MaxHeap::MaxHeap
MaxHeap()
MaxHeap constructor.
Definition: MaxHeap.cpp:32