-
Notifications
You must be signed in to change notification settings - Fork 0
/
heap.c
96 lines (81 loc) · 2.55 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
#include <string.h>
#include <assert.h>
#include "nstl-types.h"
#include "heap.h"
#include "stack.h"
#include "vector.h"
size_t __vector_item_size( Vector* V );
/* Calculate parent index */
static inline unsigned int __heap_parent( unsigned int i ) {
return i / 2;
}
/* Calculate left child index */
static inline unsigned int __heap_left( unsigned int i ) {
return i * 2;
}
/* Calculate right child index */
static inline unsigned int __heap_right( unsigned int i ) {
return ( i * 2 ) + 1;
}
inline static void swap( void* l, void* r, size_t size ) {
void* tmp = memcpy( malloc( size ), l, size );
memcpy( l, r, size );
memcpy( r, tmp, size );
free( tmp );
}
/* Comments wil assume max-heap, that is a less-than (<) compare */
/* Situation is reversed for min-heap */
static void heapify( Vector* V, cmp compare, unsigned int i ) {
void* parent = at( V, i );
void* largest = parent;
unsigned int largest_index = i;
unsigned int child = __heap_left( i );
/* Work with parent or left child? */
if( child < vector_size( V ) ) {
void* left = at( V, child );
if( compare( parent, left ) ) {
largest = left;
largest_index = child;
}
}
/* Work with right child? */
if( ++child < vector_size( V ) ) {
void* right = at( V, child );
if( compare( largest, right ) ) {
largest = right;
largest_index = child;
}
}
if( largest != parent ) {
swap( parent, largest, __vector_item_size( V ) );
heapify( V, compare, largest_index );
}
}
void heap( Vector* V, cmp compare ) {
int floor = vector_size( V ) / 2;
for( int i = floor; i >= 0; --i )
heapify( V, compare, i );
}
static void heap_increase_key( Vector* V, cmp compare, unsigned int i, void* key ) {
assert( !compare( key, at( V, i ) ) );
memcpy( at( V, i ), key, __vector_item_size( V ) );
/* V[ parent(i) ] < V[ i ] */
while( i > 0 && compare( at( V, __heap_parent( i ) ), at( V, i ) ) ) {
swap( at( V, __heap_parent( i ) ), at( V, i ),
__vector_item_size( V ) );
i = __heap_parent( i );
}
}
void heappush( Vector* V, cmp compare, void* item ) {
push( V, item );
heap_increase_key( V, compare, vector_size( V ) - 1, item );
}
void* heappop( Vector* V, cmp compare ) {
void* max = get( V, 0 );
/* Move item left and reduce heap size */
void* last = pop( V );
memmove( at( V, 0 ), last, __vector_item_size( V ) );
free( last );
heapify( V, compare, 0 );
return max;
}