Commit | Line | Data |
---|---|---|
a7868768 BA |
1 | /** |
2 | * @file Heap.c | |
3 | */ | |
4 | ||
5 | #include "cgds/Heap.h" | |
6 | ||
7 | // NOTE: no _init() method here, since Heap has no specific initialization | |
8 | ||
9 | Heap* _heap_new(size_t dataSize, OrderType hType, UInt arity) | |
10 | { | |
e45132ac BA |
11 | Heap* heap = (Heap*)safe_malloc(sizeof(Heap)); |
12 | heap->arity = arity; | |
13 | heap->hType = hType; | |
14 | heap->dataSize = dataSize; | |
15 | heap->array = _vector_new(sizeof(ItemValue)); | |
16 | return heap; | |
a7868768 BA |
17 | } |
18 | ||
19 | Heap* heap_copy(Heap* heap) | |
20 | { | |
e45132ac BA |
21 | Heap* heapCopy = _heap_new(heap->dataSize, heap->hType, heap->arity); |
22 | // HACK: vector_copy is not enough, | |
1ff641f9 | 23 | // since we also have to allocate ItemValue(->item) |
e45132ac BA |
24 | heapCopy->array->size = heap->array->size; |
25 | heapCopy->array->capacity = heap->array->capacity; | |
26 | heapCopy->array->datas = | |
1ff641f9 | 27 | (void**)safe_malloc(heap->array->capacity*sizeof(void*)); |
e45132ac BA |
28 | for (UInt i=0; i<heap->array->size; i++) |
29 | { | |
30 | heapCopy->array->datas[i] = safe_malloc(sizeof(ItemValue)); | |
31 | ItemValue itemValueCopy = (ItemValue){ | |
32 | .item=safe_malloc(heap->dataSize), | |
33 | .value=((ItemValue*)(heap->array->datas[i]))->value}; | |
34 | memcpy( | |
1ff641f9 BA |
35 | itemValueCopy.item, |
36 | ((ItemValue*)(heap->array->datas[i]))->item, | |
37 | heap->dataSize); | |
e45132ac BA |
38 | memcpy(heapCopy->array->datas[i], &itemValueCopy, sizeof(ItemValue)); |
39 | } | |
40 | return heapCopy; | |
a7868768 BA |
41 | } |
42 | ||
1ff641f9 | 43 | bool heap_empty(Heap* heap) |
a7868768 | 44 | { |
e45132ac | 45 | return vector_empty(heap->array); |
a7868768 BA |
46 | } |
47 | ||
48 | UInt heap_size(Heap* heap) | |
49 | { | |
e45132ac | 50 | return vector_size(heap->array); |
a7868768 BA |
51 | } |
52 | ||
1ff641f9 BA |
53 | // NOTE: [perf] in two following methods, full heap[k] exchanges are |
54 | // not needed; we keep track of the moving element without assigning it at | |
55 | // every step, thus saving array accesses and affectations + 'aux' tmp memory. | |
a7868768 BA |
56 | // --> this is not the most natural way of writing these functions. |
57 | ||
58 | void _heap_bubble_up(Heap* heap, UInt startIndex) | |
59 | { | |
e45132ac BA |
60 | UInt currentIndex = startIndex; |
61 | ItemValue* startItemValue = heap->array->datas[startIndex]; | |
62 | while (true) | |
63 | { | |
64 | // get parent | |
65 | UInt nextIndex = currentIndex / heap->arity; | |
66 | Real nextValue = ((ItemValue*)(heap->array->datas[nextIndex]))->value; | |
67 | // compare to parent (if applicable) | |
68 | if (currentIndex == 0 || | |
69 | (heap->hType == MIN_T && startItemValue->value >= nextValue) || | |
70 | (heap->hType == MAX_T && startItemValue->value <= nextValue)) | |
71 | { | |
72 | // moving element has landed: apply final affectation | |
73 | heap->array->datas[currentIndex] = startItemValue; | |
74 | break; | |
75 | } | |
76 | // move one level up: the parent goes one level down | |
77 | heap->array->datas[currentIndex] = heap->array->datas[nextIndex]; | |
78 | currentIndex = nextIndex; | |
79 | } | |
a7868768 BA |
80 | } |
81 | ||
82 | void _heap_bubble_down(Heap* heap, UInt startIndex) | |
83 | { | |
e45132ac BA |
84 | UInt currentIndex = startIndex; |
85 | ItemValue* startItemValue = heap->array->datas[startIndex]; | |
86 | while (true) | |
87 | { | |
88 | if (currentIndex * heap->arity >= heap->array->size) | |
89 | { | |
90 | // moving element has landed (in a leaf): apply final affectation | |
91 | heap->array->datas[currentIndex] = startItemValue; | |
92 | break; | |
93 | } | |
94 | // find top child (min or max) | |
95 | UInt topChildIndex; | |
96 | Real topChildValue = (heap->hType == MIN_T ? INFINITY : -INFINITY); | |
97 | for (Int i=0; i<heap->arity; i++) | |
98 | { | |
99 | UInt childIndex = i + currentIndex * heap->arity; | |
100 | if (childIndex >= heap->array->size) | |
101 | break; | |
102 | Real childValue = ((ItemValue*)(heap->array->datas[childIndex]))->value; | |
103 | if ((heap->hType == MIN_T && childValue < topChildValue) || | |
104 | (heap->hType == MAX_T && childValue > topChildValue)) | |
105 | { | |
106 | topChildIndex = childIndex; | |
107 | topChildValue = childValue; | |
108 | } | |
109 | } | |
110 | // compare to top child | |
111 | if ((heap->hType == MIN_T && startItemValue->value > topChildValue) || | |
112 | (heap->hType == MAX_T && startItemValue->value < topChildValue)) | |
113 | { | |
114 | // move one level down: the child goes one level up | |
115 | heap->array->datas[currentIndex] = heap->array->datas[topChildIndex]; | |
116 | } | |
117 | else | |
118 | { | |
119 | // moving element has landed: apply final affectation | |
120 | heap->array->datas[currentIndex] = startItemValue; | |
121 | break; | |
122 | } | |
123 | currentIndex = topChildIndex; | |
124 | } | |
a7868768 BA |
125 | } |
126 | ||
127 | void _heap_insert(Heap* heap, void* item, Real value) | |
128 | { | |
e45132ac | 129 | ItemValue itemValue = |
1ff641f9 | 130 | (ItemValue){.item=safe_malloc(heap->dataSize), .value=value}; |
e45132ac BA |
131 | memcpy(itemValue.item, item, heap->dataSize); |
132 | _vector_push(heap->array, &itemValue); | |
133 | _heap_bubble_up(heap, heap->array->size-1); | |
a7868768 BA |
134 | } |
135 | ||
136 | void _heap_modify(Heap* heap, UInt index, Real newValue) | |
137 | { | |
e45132ac BA |
138 | double oldValue = ((ItemValue*)(heap->array->datas[index]))->value; |
139 | ((ItemValue*)(heap->array->datas[index]))->value = newValue; | |
140 | if ((heap->hType == MIN_T && newValue > oldValue) || | |
141 | (heap->hType == MAX_T && newValue < oldValue)) | |
142 | { | |
143 | _heap_bubble_down(heap, index); | |
144 | } | |
145 | else | |
146 | _heap_bubble_up(heap, index); | |
a7868768 BA |
147 | } |
148 | ||
149 | void _heap_remove(Heap* heap, UInt index) | |
150 | { | |
e45132ac BA |
151 | safe_free(((ItemValue*)(heap->array->datas[index]))->item); |
152 | ItemValue* tmp = heap->array->datas[index]; | |
153 | heap->array->datas[index] = heap->array->datas[heap_size(heap)-1]; | |
154 | heap->array->datas[heap_size(heap)-1] = tmp; | |
155 | vector_pop(heap->array); | |
156 | if (heap->array->size > 0) | |
157 | _heap_bubble_down(heap, index); | |
a7868768 BA |
158 | } |
159 | ||
160 | ItemValue* heap_top_raw(Heap* heap) | |
161 | { | |
e45132ac | 162 | return (ItemValue*)(heap->array->datas[0]); |
a7868768 BA |
163 | } |
164 | ||
165 | void heap_pop(Heap* heap) | |
166 | { | |
e45132ac | 167 | _heap_remove(heap, 0); |
a7868768 BA |
168 | } |
169 | ||
170 | void heap_clear(Heap* heap) | |
171 | { | |
e45132ac BA |
172 | for (UInt i = 0; i < heap->array->size; i++) |
173 | { | |
174 | // Extra memory releases which wouldn't be done in vector_clear() | |
175 | safe_free(((ItemValue*)(heap->array->datas[i]))->item); | |
176 | //safe_free((ItemValue*)heap->array->datas[i]); | |
177 | } | |
178 | vector_clear(heap->array); | |
a7868768 BA |
179 | } |
180 | ||
181 | void heap_destroy(Heap* heap) | |
182 | { | |
e45132ac BA |
183 | heap_clear(heap); |
184 | safe_free(heap->array); | |
185 | safe_free(heap); | |
a7868768 | 186 | } |