Some fixes + improvements (Vector) + code reformatting
[cgds.git] / src / Heap.c
CommitLineData
a7868768
BA
1/**
2 * @file Heap.c
3 */
4
5#include "cgds/Heap.h"
6
eed1b5d2 7// NOTE: no init() method here, since Heap has no specific initialization
a7868768
BA
8
9Heap* _heap_new(size_t dataSize, OrderType hType, UInt arity)
10{
1d60b10a 11 Heap* heap = (Heap*) safe_malloc(sizeof(Heap));
e45132ac
BA
12 heap->arity = arity;
13 heap->hType = hType;
1d60b10a
BA
14 heap->items = _vector_new(dataSize);
15 heap->values = _vector_new(sizeof(Real));
e45132ac 16 return heap;
a7868768
BA
17}
18
19Heap* heap_copy(Heap* heap)
20{
1d60b10a
BA
21 Heap* heapCopy = (Heap*) safe_malloc(sizeof(Heap));
22 heapCopy->arity = heap->arity;
23 heapCopy->hType = heap->hType;
24 heapCopy->items = vector_copy(heap->items);
25 heapCopy->values = vector_copy(heap->values);
e45132ac 26 return heapCopy;
a7868768
BA
27}
28
1ff641f9 29bool heap_empty(Heap* heap)
a7868768 30{
1d60b10a 31 return vector_empty(heap->items);
a7868768
BA
32}
33
34UInt heap_size(Heap* heap)
35{
1d60b10a 36 return vector_size(heap->items);
a7868768
BA
37}
38
1ff641f9
BA
39// NOTE: [perf] in two following methods, full heap[k] exchanges are
40// not needed; we keep track of the moving element without assigning it at
41// every step, thus saving array accesses and affectations + 'aux' tmp memory.
a7868768
BA
42// --> this is not the most natural way of writing these functions.
43
44void _heap_bubble_up(Heap* heap, UInt startIndex)
45{
1d60b10a
BA
46 if (startIndex == 0)
47 // Nothing to do in this case
48 return;
e45132ac 49 UInt currentIndex = startIndex;
1d60b10a
BA
50 void* startItem = _vector_get(heap->items, startIndex);
51 Real startValue = *((Real*)(_vector_get(heap->values, startIndex)));
52 bool startItemReallocated = false;
e45132ac
BA
53 while (true)
54 {
1d60b10a
BA
55 bool land = (currentIndex == 0), //at root: can't go up
56 applyExchange = true;
57 if (!land)
58 {
59 // Get parent and compare to it
60 UInt nextIndex = (currentIndex - 1) / heap->arity;
61 Real nextValue = *((Real*)(_vector_get(heap->values, nextIndex)));
62 land = (
63 (heap->hType == MIN_T && startValue >= nextValue) ||
64 (heap->hType == MAX_T && startValue <= nextValue)
65 );
66 if (!land)
67 {
68 // Move one level up: the parent goes one level down
69 if (currentIndex == startIndex)
70 {
71 // Save startItem (because *startItem is about to be changed)
72 void* newStartItem = safe_malloc(heap->items->dataSize);
73 memcpy(newStartItem, startItem, heap->items->dataSize);
74 startItem = newStartItem;
75 startItemReallocated = true;
76 }
77 void* nextItem = _vector_get(heap->items, nextIndex);
78 _vector_set(heap->items, currentIndex, nextItem);
79 _vector_set(heap->values, currentIndex, &nextValue);
80 currentIndex = nextIndex;
81 continue;
82 }
83 // At correct relative place: will now land
84 if (currentIndex == startIndex)
85 applyExchange = false;
86 }
87 if (applyExchange)
e45132ac 88 {
1d60b10a
BA
89 _vector_set(heap->items, currentIndex, startItem);
90 _vector_set(heap->values, currentIndex, &startValue);
e45132ac 91 }
1d60b10a 92 break;
e45132ac 93 }
1d60b10a
BA
94 if (startItemReallocated)
95 safe_free(startItem);
a7868768
BA
96}
97
98void _heap_bubble_down(Heap* heap, UInt startIndex)
99{
1d60b10a
BA
100 if (startIndex * heap->arity + 1 >= heap->items->size)
101 // Nothing to do: already in a leaf
102 return;
e45132ac 103 UInt currentIndex = startIndex;
1d60b10a
BA
104 void* startItem = _vector_get(heap->items, startIndex);
105 Real startValue = *((Real*)(_vector_get(heap->values, startIndex)));
106 bool startItemReallocated = false;
e45132ac
BA
107 while (true)
108 {
1d60b10a
BA
109 bool land = (currentIndex * heap->arity + 1 >= heap->items->size),
110 applyExchange = true;
111 if (!land)
e45132ac 112 {
1d60b10a
BA
113 // Find top child (min or max)
114 UInt topChildIndex;
115 Real topChildValue = (heap->hType == MIN_T ? INFINITY : -INFINITY);
116 for (UInt i = 1; i <= heap->arity; i++)
e45132ac 117 {
1d60b10a
BA
118 UInt childIndex = currentIndex * heap->arity + i;
119 if (childIndex >= heap->items->size)
120 break;
121 Real childValue = *((Real*)(_vector_get(heap->values, childIndex)));
122 if (
123 (heap->hType == MIN_T && childValue < topChildValue) ||
124 (heap->hType == MAX_T && childValue > topChildValue)
125 ) {
126 topChildIndex = childIndex;
127 topChildValue = childValue;
128 }
e45132ac 129 }
1d60b10a
BA
130 // Compare to top child
131 land = (
132 (heap->hType == MIN_T && startValue <= topChildValue) ||
133 (heap->hType == MAX_T && startValue >= topChildValue)
134 );
135 if (!land)
136 {
137 // Move one level down: the child goes one level up
138 if (currentIndex == startIndex)
139 {
140 // Save startItem (because *startItem is about to be changed)
141 void* newStartItem = safe_malloc(heap->items->dataSize);
142 memcpy(newStartItem, startItem, heap->items->dataSize);
143 startItem = newStartItem;
144 startItemReallocated = true;
145 }
146 void* topChildItem = _vector_get(heap->items, topChildIndex);
147 _vector_set(heap->items, currentIndex, topChildItem);
148 _vector_set(heap->values, currentIndex, &topChildValue);
149 currentIndex = topChildIndex;
150 continue;
151 }
152 // At correct relative place: will now land
153 if (currentIndex == startIndex)
154 applyExchange = false;
e45132ac 155 }
1d60b10a 156 if (applyExchange)
e45132ac 157 {
1d60b10a
BA
158 // Moving element has landed (in a leaf): apply final affectation
159 _vector_set(heap->items, currentIndex, startItem);
160 _vector_set(heap->values, currentIndex, &startValue);
e45132ac 161 }
1d60b10a 162 break;
e45132ac 163 }
1d60b10a
BA
164 if (startItemReallocated)
165 safe_free(startItem);
a7868768
BA
166}
167
168void _heap_insert(Heap* heap, void* item, Real value)
169{
1d60b10a
BA
170 _vector_push(heap->items, item);
171 _vector_push(heap->values, &value);
172 _heap_bubble_up(heap, heap->items->size - 1);
a7868768
BA
173}
174
1d60b10a 175Int _heap_get_index(Heap* heap, void* item)
a7868768 176{
1d60b10a 177 for (Int index = 0; index < heap->items->size; index++)
e45132ac 178 {
1d60b10a
BA
179 if (
180 memcmp(
181 heap->items->datas + index * heap->items->dataSize,
182 item,
183 heap->items->dataSize
184 ) == 0
185 ) {
186 return index;
187 }
188 }
189 return -1;
190}
191
192void _heap_modify(Heap* heap, void* item, Real newValue)
193{
194 // First, find index of the item:
195 const Int index = _heap_get_index(heap, item);
196 if (index < 0)
197 // Element not found
198 return;
199 Real oldValue = *((Real*)_vector_get(heap->values, index));
200 _vector_set(heap->values, index, &newValue);
201 if (
202 (heap->hType == MIN_T && newValue > oldValue) ||
203 (heap->hType == MAX_T && newValue < oldValue)
204 ) {
e45132ac
BA
205 _heap_bubble_down(heap, index);
206 }
207 else
208 _heap_bubble_up(heap, index);
a7868768
BA
209}
210
1d60b10a 211void _heap_remove_at_index(Heap* heap, Int index)
a7868768 212{
1d60b10a
BA
213 const bool removeLast = (index == heap->items->size - 1);
214 if (!removeLast)
215 {
216 _vector_set(
217 heap->items,
218 index,
219 _vector_get(heap->items, heap->items->size - 1));
220 _vector_set(
221 heap->values,
222 index,
223 _vector_get(heap->values, heap->values->size - 1));
224 }
225 vector_pop(heap->items);
226 vector_pop(heap->values);
227 if (!removeLast && heap->items->size > 0)
e45132ac 228 _heap_bubble_down(heap, index);
a7868768
BA
229}
230
1d60b10a
BA
231void _heap_remove(Heap* heap, void* item)
232{
233 // First, find index of the item:
234 const Int index = _heap_get_index(heap, item);
235 if (index >= 0)
236 _heap_remove_at_index(heap, index);
237}
238
239ItemValue _heap_top(Heap* heap)
a7868768 240{
1d60b10a
BA
241 ItemValue top;
242 top.item = _vector_get(heap->items, 0);
243 vector_get(heap->values, 0, top.value);
244 return top;
a7868768
BA
245}
246
247void heap_pop(Heap* heap)
248{
1d60b10a 249 _heap_remove_at_index(heap, 0);
a7868768
BA
250}
251
252void heap_clear(Heap* heap)
253{
1d60b10a
BA
254 vector_clear(heap->items);
255 vector_clear(heap->values);
a7868768
BA
256}
257
258void heap_destroy(Heap* heap)
259{
1d60b10a
BA
260 vector_destroy(heap->items);
261 vector_destroy(heap->values);
e45132ac 262 safe_free(heap);
a7868768 263}