-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathheap.c
360 lines (313 loc) · 9.22 KB
/
heap.c
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
/*
* heap.c
*
* Created: 10/15/2013 7:41:35 PM
* Author: Greg Cook
*
* Heap data structure
*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "heap.h"
/**
* Validation function
* @param heap Heap opject
* @return True if heap is a valid structure
*/
static bool heap_valid(const heap_t *heap);
/**
* Get parent node of current node
* @param index Index of current node in internal array
* @return index of parent node in internal array
*/
static inline heap_index_t heap_node_parent(heap_index_t index) {
return (index - 1) / 2;
}
/**
* Get left child of current node
* @param index Index of current node in internal array
* @return index of left child node in internal array
*/
static inline heap_index_t heap_node_left_child(heap_index_t index) {
return index * 2 + 1;
}
/**
* Get right child of current node
* @param index Index of current node in internal array
* @return index of right child node in internal array
*/
static inline heap_index_t heap_node_right_child(heap_index_t index) {
return index * 2 + 2;
}
/**
* Get key value from heap data
* @param heap Heap opject
* @param index Index of node
* @return key value from data object contained by node
*/
static inline heap_key_t heap_get_key(const heap_t *heap, heap_index_t index) {
return ( heap->get_key(heap->data[index]) );
}
/**
* Compare two nodes using max heap compare strategy
* @param heap Heap opject
* @param a Index of node a
* @param b Index of node b
* @return True if key(a) > key(b)
*/
static inline bool heap_cmp_max(const heap_t *heap, heap_index_t a, heap_index_t b) {
return ( heap_get_key(heap, a) > heap_get_key(heap, b) );
}
/**
* Compare two nodes using min heap compare strategy
* @param heap Heap opject
* @param a Index of node a
* @param b Index of node b
* @return True if key(a) < key(b)
*/
static inline bool heap_cmp_min(const heap_t *heap, heap_index_t a, heap_index_t b) {
return ( heap_get_key(heap, a) < heap_get_key(heap, b) );
}
/**
* Swap two nodes in a heap
* @param heap Heap opject
* @param a Index of node a
* @param b Index of node b
* @return void
*/
static inline void heap_swap(heap_t *heap, heap_index_t a, heap_index_t b) {
void *temp = heap->data[a];
heap->data[a] = heap->data[b];
heap->data[b] = temp;
}
/**
* Heapify up implementation
* @param heap Heap opject
* @param index Index of node to move up
* @return void
*/
static void heap_heapify_up(heap_t *heap, heap_index_t index) {
heap_index_t current = index;
heap_index_t parent = heap_node_parent(current);
while (current > 0 && !(heap->cmp(heap, parent, current))) {
heap_swap(heap, parent, current);
current = parent;
parent = heap_node_parent(current);
}
}
/**
* Heapify node in heap
* @param heap Heap opject
* @param index Index of node to heapify
* @return void
*/
static void heap_heapify(heap_t *heap, heap_index_t index) {
heap_index_t left = heap_node_left_child(index);
heap_index_t right = heap_node_right_child(index);
heap_index_t minmax = index;
if (left < heap->size && heap->cmp(heap, left, index))
minmax = left;
else
minmax = index;
if (right < heap->size && heap->cmp(heap, right, minmax))
minmax = right;
if (minmax != index) {
heap_swap(heap, index, minmax);
heap_heapify(heap, minmax);
}
}
/**
* Get heap head
* @param heap Heap opject
* @return Head node of heap
*/
static inline void *heap_head(const heap_t *heap) {
return heap->data[0];
}
/**
* Determine if Heap is empty
* @param heap Heap opject
* @return True if heap has no elements
*/
static inline bool heap_is_empty(const heap_t *heap) {
return (heap->size == 0);
}
/**
* Determine if heap is full
* @param heap Heap opject
* @return True if no more elements can be inserted
*/
static inline bool heap_is_full(const heap_t *heap) {
return (heap->size == heap->max_size);
}
/**
* Initialize heap structure
* @param heap Heap opject
* @param type Type of heap, one of (HEAP_MAX, HEAP_MIN)
* @param data_size Number of elements in data
* @param data Heap storage array (you need to allocate this and pass it in)
* @param get_key Function that returns key from a data element
* @return void
*/
static void heap_init(heap_t *heap, heap_type_t type, int data_size, void *data, heap_get_key_fp get_key) {
heap->size = 0;
heap->max_size = data_size;
heap->data = data;
if (type == HEAP_MAX)
heap->cmp = heap_cmp_max;
else
heap->cmp = heap_cmp_min;
heap->get_key = get_key;
int i;
for (i = 0; i < data_size; i++)
heap->data[i] = NULL;
assert(heap_valid(heap) && "Heap invalid");
}
/**
* Statically define the data array in a data structure
* @note this is dumb...don't use this, but its the way I wrote it
* initialially and it is still used somewhere.
*/
static heap_t *heap_static_init(static_heap_t *st_heap, heap_type_t type, heap_get_key_fp get_key) {
heap_t *structure = &st_heap->_structure;
void *data = &st_heap->_data;
heap_init(structure, type, STATIC_HEAP_SIZE, data, get_key);
return structure;
}
/**
* Insert new element into heap
* @param heap Heap opject
* @param new Object to insert
* @return True if object was inserted, false if heap was full
*/
static bool heap_insert(heap_t * restrict heap, void * restrict new) {
if (!heap_is_full(heap)) {
int index = heap->size;
heap->size++;
heap->data[index] = new;
heap_heapify_up(heap, index);
assert(heap_valid(heap) && "Heap invalid");
return true;
}
return false;
}
/**
* Remove and return object from head of heap
* @param heap Heap opject
* @return Object from head of heap, or NULL if heap is empty
*/
static void *heap_remove_head(heap_t *heap) {
void *result = NULL;
if (!heap_is_empty(heap)) {
result = heap->data[0];
heap->data[0] = heap->data[heap->size - 1]; // last element
heap->data[heap->size - 1] = NULL;
heap->size--;
heap_heapify(heap, 0);
}
assert(heap_valid(heap) && "Heap invalid");
return result;
}
/**
* Heap class interface
*/
heap_class_t Heap = {
.static_init = heap_static_init,
.init = heap_init,
.insert = heap_insert,
.remove_head = heap_remove_head,
.head = heap_head,
.is_empty = heap_is_empty,
.is_full = heap_is_full
};
/************************************************************************/
/* Debug/Validation Code */
/************************************************************************/
/**
* Does the heap maintain the max heap property
* @param heap Heap opject
* @param index Index of node
* @return true if max heap property holds for node
*/
static inline bool heap_max_heap_property(const heap_t *heap, int index) {
int parent = heap_node_parent(index);
return (heap_get_key(heap, parent) >= heap_get_key(heap, index));
}
/**
* Does the heap maintain the min heap property
* @param heap Heap opject
* @param index Index of node
* @return true if max heap property holds for node
*/
static inline bool heap_min_heap_property(const heap_t *heap, int index) {
int parent = heap_node_parent(index);
return (heap_get_key(heap, parent) <= heap_get_key(heap, index));
}
/**
* Is the heap valid
* @param heap Heap opject
* @return True if the heap is valid
*/
static bool heap_valid(const heap_t *heap) {
bool error = false;
// heap is not null
error |= (heap == NULL);
assert(!error && "heap ptr is null");
// cannot continue if error
if (error) return !error;
// size >= 0
error |= (heap->size < 0);
assert(!error && "heap size is negative");
// size <= max_size
error |= (heap->size > heap->max_size);
assert(!error && "heap size is larger than max size");
// cmp is not null
error |= (heap->cmp == NULL);
assert(!error && "heap cmp function ptr is null");
// get_key is not null
error |= (heap->get_key == NULL);
assert(!error && "heap get_key function ptr is null");
int i;
for (i = 0; i < heap->max_size; i++) {
if (i < heap->size) {
error |= (heap->data[i] == NULL);
assert(!error && "valid data space is NULL");
}
else {
// data entry must be NULL
error |= (heap->data[i] != NULL);
assert(!error && "empty data space not NULL");
}
}
// cannot continue if error
if (error) return !error;
// determine heap type
bool (*heap_property)(const heap_t*, int);
if (heap->cmp == heap_cmp_max)
heap_property = heap_max_heap_property;
else
heap_property = heap_min_heap_property;
for (i = 1; i < heap->size; i++) {
error |= (!heap_property(heap, i));
assert(!error && "heap property not maintained");
}
return !error;
}
/**
* Generic heap dispaly function
* @param heap Heap opject
* @return void
*/
static void heap_display(const heap_t *heap) {
int i;
for (i = 0; i < heap->max_size; i++) {
if (i < heap->size) {
printf("%d:%d ", i, (int)(heap->get_key(heap->data[i])));
}
else {
printf("%d:%p ", i, heap->data[i]);
}
}
printf("\n");
}