CUBRID Engine  latest
binaryheap.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * binaryheap.c - binary heap implementation
21  */
22 #include <stdlib.h>
23 #include <assert.h>
24 #include "binaryheap.h"
25 #include "memory_alloc.h"
26 #include "error_manager.h"
27 
28 #define BH_PARENT(i) ((i - 1)/2)
29 #define BH_LEFT(i) (2*(i) + 1)
30 #define BH_RIGHT(i) (2*(i)+2)
31 #define BH_ELEMENT_COPY(heap, dest, src) (memcpy (dest, src, (heap)->elem_size))
32 
33 #define BH_SWAP(heap, left, right) \
34  do \
35  { \
36  BH_ELEMENT_COPY (heap, (heap)->swap_buf, BH_ELEMENT (heap, left)); \
37  BH_ELEMENT_COPY (heap, BH_ELEMENT (heap, left), BH_ELEMENT (heap, right)); \
38  BH_ELEMENT_COPY (heap, BH_ELEMENT (heap, right), (heap)->swap_buf); \
39  } \
40  while (0)
41 
42 #define BH_CMP(heap, l, r) \
43  (heap->cmp_func (BH_ELEMENT (heap, l), BH_ELEMENT (heap, r), heap->cmp_arg))
44 
45 
46 static void bh_up_heap (BINARY_HEAP * heap, int index);
47 static void bh_replace_max (BINARY_HEAP * heap, void *elem);
48 
49 /*
50  * bh_up_heap () - push an element up the heap to the correct position
51  * return : void
52  * heap (in) : heap
53  * index (in) : index of the element to
54  */
55 static void
57 {
58  if (index == 0)
59  {
60  return;
61  }
62 
63  if (BH_CMP (heap, BH_PARENT (index), index) == BH_LT)
64  {
65  /* swap element with parent */
66  BH_SWAP (heap, index, BH_PARENT (index));
67  /* shift parent */
68  bh_up_heap (heap, BH_PARENT (index));
69  }
70 }
71 
72 /*
73  * bh_down_heap () - push an element down the heap to its correct position
74  * return : void
75  * heap (in) : heap
76  * index (in) : element index
77  */
78 void
80 {
81  int left = BH_LEFT (index);
82  int right = BH_RIGHT (index);
83  int largest = index;
84 
85  if (left <= heap->element_count - 1 && BH_CMP (heap, left, largest) == BH_GT)
86  {
87  largest = left;
88  }
89 
90  if (right <= heap->element_count - 1 && BH_CMP (heap, right, largest) == BH_GT)
91  {
92  largest = right;
93  }
94 
95  if (largest != index)
96  {
97  BH_SWAP (heap, index, largest);
98  bh_down_heap (heap, largest);
99  }
100 }
101 
102 /*
103  * bh_create () - create an empty heap
104  * return : heap or NULL
105  * max_capacity (in): maximum capacity of the heap
106  * elem_size (in) : the size of one heap element.
107  * cmp_func (in) : pointer to the comparison function
108  * cmp_arg (in) : argument to be passed to the comparison function
109  *
110  * Note: This implementation considers the heap to be a MAX heap (i.e.: the root of the heap is the "largest" element).
111  * To use the heap as a MIN heap, callers can use the comparison function to inverse the comparison
112  */
113 BINARY_HEAP *
114 bh_create (THREAD_ENTRY * thread_p, int max_capacity, int elem_size, bh_key_comparator cmp_func, BH_CMP_ARG cmp_arg)
115 {
116  BINARY_HEAP *heap = NULL;
117 
118  heap = (BINARY_HEAP *) db_private_alloc (thread_p, sizeof (BINARY_HEAP));
119  if (heap == NULL)
120  {
122  return NULL;
123  }
124 
125  heap->members = db_private_alloc (thread_p, max_capacity * elem_size);
126  if (heap->members == NULL)
127  {
128  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, max_capacity * elem_size);
129  db_private_free (thread_p, heap);
130  return NULL;
131  }
132  heap->swap_buf = db_private_alloc (thread_p, elem_size);
133  if (heap->swap_buf == NULL)
134  {
136  db_private_free (thread_p, heap->members);
137  db_private_free (thread_p, heap);
138  return NULL;
139  }
140  memset (heap->members, 0, max_capacity * elem_size);
141  heap->max_capacity = max_capacity;
142  heap->elem_size = elem_size;
143  heap->cmp_func = cmp_func;
144  heap->cmp_arg = cmp_arg;
145  heap->element_count = 0;
146  heap->state = BH_HEAP_CONSISTENT;
147 
148  return heap;
149 }
150 
151 /*
152  * bh_destroy () - destroy a binary heap
153  * return : void
154  * heap (in) : heap
155  */
156 void
157 bh_destroy (THREAD_ENTRY * thread_p, BINARY_HEAP * heap)
158 {
159  if (heap != NULL)
160  {
161  if (heap->members != NULL)
162  {
163  db_private_free (thread_p, heap->members);
164  }
165  if (heap->swap_buf != NULL)
166  {
167  db_private_free (thread_p, heap->swap_buf);
168  }
169  db_private_free (thread_p, heap);
170  }
171 }
172 
173 /*
174  * bh_add () - add an element to the heap without preserving the heap property
175  * return : error code if capacity is exceeded or NO_ERROR
176  * heap (in) : heap
177  * elem (in) : new element
178  *
179  * Note: This function is provided as a convenience to speed up heap creation.
180  * It is more efficient to load about half the heap with unordered elements and call bh_build_heap to restore the
181  * heap property.
182  */
183 int
184 bh_add (BINARY_HEAP * heap, void *elem)
185 {
186  assert (heap != NULL);
187  assert (elem != NULL);
188 
189  heap->state = BH_HEAP_INCONSISTENT;
190 
191  if (heap->element_count >= heap->max_capacity)
192  {
195  }
196  BH_ELEMENT_COPY (heap, BH_ELEMENT (heap, heap->element_count), elem);
197  heap->element_count++;
198 
199  return NO_ERROR;
200 }
201 
202 /*
203  * bh_insert () - insert an element in the correct position in the heap
204  * return : error code or NO_ERROR
205  * heap (in) : heap
206  * elem (in) : new element
207  */
208 int
209 bh_insert (BINARY_HEAP * heap, void *elem)
210 {
211  assert (heap != NULL);
212  assert (elem != NULL);
213 
214  if (heap->element_count != 0)
215  {
217  }
218  else
219  {
220  /* This is the first element, set the consistent property */
221  heap->state = BH_HEAP_CONSISTENT;
222  }
223 
224  if (heap->element_count >= heap->max_capacity)
225  {
228  }
229 
230  BH_ELEMENT_COPY (heap, BH_ELEMENT (heap, heap->element_count), elem);
231  heap->element_count++;
232  bh_up_heap (heap, heap->element_count - 1);
233 
234  return NO_ERROR;
235 }
236 
237 /*
238  * bh_try_insert () - insert an element into the heap if heap hasn't reached the full capacity or if new element is
239  * smaller than the top element
240  * return : BH_TRY_INSERT_RESULT
241  * - BH_TRY_INSERT_ACCEPTED if the heap was not full
242  * - BH_TRY_INSERT_REJECTED if the heap was full and new element was rejected
243  * - BH_TRY_INSERT_REPLACED if the heap was full and new element replaced old root.
244  * heap (in) : heap
245  * elem (in) : new element
246  * replaced (out) : value of replaced element (if replaced).
247  */
249 bh_try_insert (BINARY_HEAP * heap, void *elem, void *replaced)
250 {
251  assert (heap != NULL);
252  assert (elem != NULL);
253 
254  if (heap->element_count < heap->max_capacity)
255  {
256  bh_insert (heap, elem);
257  return BH_TRY_INSERT_ACCEPTED;
258  }
259  /* if root is larger than new element, replace root */
260  if (heap->cmp_func (BH_ROOT (heap), elem, heap->cmp_arg) == BH_GT)
261  {
262  if (replaced != NULL)
263  {
264  BH_ELEMENT_COPY (heap, replaced, BH_ROOT (heap));
265  }
266  bh_replace_max (heap, elem);
267  return BH_TRY_INSERT_REPLACED;
268  }
269  return BH_TRY_INSERT_REJECTED;
270 }
271 
272 /*
273  * bh_build_heap () - restore the heap property in an unordered heap
274  * return : void
275  * heap (in) : heap
276  */
277 void
279 {
280  int i;
281 
282  assert (heap != NULL);
283 
284  if (heap->state == BH_HEAP_CONSISTENT)
285  {
286  /* already consistent, nothing to build */
287  return;
288  }
289 
290  for (i = BH_PARENT (heap->element_count - 1); i >= 0; i--)
291  {
292  bh_down_heap (heap, i);
293  }
294  heap->state = BH_HEAP_CONSISTENT;
295 }
296 
297 /*
298  * bh_extract_max () - pop the largest element from a heap
299  * return : true if heap is not empty and element is extracted, false if heap is empty.
300  * heap (in) : heap
301  * extract_elem (out) : extracted element.
302  */
303 bool
304 bh_extract_max (BINARY_HEAP * heap, void *extract_elem)
305 {
306  assert (heap != NULL);
307  assert (extract_elem != NULL);
308 
309  if (heap->element_count <= 0)
310  {
311  /* empty */
312  return false;
313  }
314  /* extract algorithm is:
315  * 1. replace root with last element on the last level.
316  * 2. recursive down-swap new root with children until the order is correct.
317  */
318  /* decrement element count; this also becomes the index of last element in heap */
319  heap->element_count--;
320  /* Copy root. */
321  BH_ELEMENT_COPY (heap, extract_elem, BH_ROOT (heap));
322  if (heap->element_count > 0)
323  {
324  /* replace root with last element. */
325  BH_ELEMENT_COPY (heap, BH_ROOT (heap), BH_ELEMENT (heap, heap->element_count));
326  /* down-swap until order is correct again */
327  bh_down_heap (heap, 0);
328  }
329  return true;
330 }
331 
332 /*
333  * bh_replace_max () - replace the largest element from a heap with a new
334  * element
335  * return : void
336  * heap (in) : heap
337  * elem (in) : new element
338  */
339 void
340 bh_replace_max (BINARY_HEAP * heap, void *elem)
341 {
342  assert (heap != NULL);
343  assert (elem != NULL);
344 
345  /* heap_max greater than elem */
346  BH_ELEMENT_COPY (heap, BH_ROOT (heap), elem);
347  bh_down_heap (heap, 0);
348 }
349 
350 /*
351  * bh_peek_max () - peek the value of the largest element in the heap
352  * return : true if heap is not empty and element is extracted, false if heap is empty.
353  * heap (in) : heap
354  * peek_elem (out) : peeked value of largest element.
355  */
356 bool
357 bh_peek_max (BINARY_HEAP * heap, void *peek_elem)
358 {
359  assert (heap != NULL);
360  assert (peek_elem != NULL);
361 
362  if (heap->element_count == 0)
363  {
364  return false;
365  }
366  BH_ELEMENT_COPY (heap, peek_elem, BH_ROOT (heap));
367  return true;
368 }
369 
370 /*
371  * bh_to_sorted_array () - transform a binary heap into a sorted array
372  * return : void
373  * heap (in) : heap
374  *
375  * Note: the array is sorted smallest to largest (smallest element on the first position)
376  */
377 void
379 {
380  int element_count;
381 
382  assert (heap != NULL);
383 
384  element_count = heap->element_count;
385  /* while has elements, extract max */
386  while (heap->element_count > 1)
387  {
388  BH_SWAP (heap, 0, heap->element_count - 1);
389  heap->element_count--;
390  bh_down_heap (heap, 0);
391  }
392  /* no longer consistent */
393  heap->state = BH_SORTED_ARRAY;
394 
395  /* reset element count */
396  heap->element_count = element_count;
397 }
398 
399 #if defined(CUBRID_DEBUG)
400 /*
401  * bh_tests_consistent () - test if the elements stored in the heap
402  * have the heap property
403  * return : true if the heap is consistent, false otherwise
404  * heap (in) : heap
405  */
406 int
407 bh_tests_consistent (BINARY_HEAP * heap)
408 {
409  int i;
410 
411  assert (heap != NULL);
412 
413  if (heap->element_count <= 1)
414  {
415  /* at most one element, it is consistent */
416  heap->state = BH_HEAP_CONSISTENT;
417  return true;
418  }
419 
420  /* test heap property: CHILD <= PARENT */
421  for (i = 1; i < heap->element_count; i++)
422  {
423  if (BH_CMP (heap, BH_PARENT (i), i) == BH_LT)
424  {
425  heap->state = BH_HEAP_INCONSISTENT;
426  return false;
427  }
428  }
429  heap->state = BH_HEAP_CONSISTENT;
430  return true;
431 }
432 #endif
433 
434 /*
435  * bh_element_at () - get element at specified index from the array
436  * return : element
437  * heap (in) : heap
438  * index (in) : index
439  * elem (out) : element at index.
440  */
441 void
442 bh_element_at (BINARY_HEAP * heap, int index, void *elem)
443 {
444  assert (heap != NULL);
445  assert (index < heap->element_count);
446  assert (elem != NULL);
447 
448  BH_ELEMENT_COPY (heap, elem, BH_ELEMENT (heap, index));
449 }
450 
451 /*
452  * bh_is_consistent () - return true if heap is in consistent state
453  * return : true or false
454  * heap (in) : heap
455  */
456 bool
458 {
459  assert (heap != NULL);
460  return (heap->state == BH_HEAP_CONSISTENT);
461 }
462 
463 /*
464  * bh_is_full () - test if heap holds maximum capacity elements
465  * return : true if heap is at maximum capacity
466  * heap (in) : heap
467  */
468 bool
470 {
471  assert (heap != NULL);
472  return (heap->element_count >= heap->max_capacity);
473 }
#define ER_BINARY_HEAP_OUT_OF_RANGE
Definition: error_code.h:1410
#define NO_ERROR
Definition: error_code.h:46
bool bh_is_consistent(BINARY_HEAP *heap)
Definition: binaryheap.c:457
#define BH_SWAP(heap, left, right)
Definition: binaryheap.c:33
void bh_down_heap(BINARY_HEAP *heap, int index)
Definition: binaryheap.c:79
void bh_to_sorted_array(BINARY_HEAP *heap)
Definition: binaryheap.c:378
void bh_element_at(BINARY_HEAP *heap, int index, void *elem)
Definition: binaryheap.c:442
#define assert_release(e)
Definition: error_manager.h:96
static void bh_replace_max(BINARY_HEAP *heap, void *elem)
Definition: binaryheap.c:340
int element_count
Definition: binaryheap.h:71
int bh_insert(BINARY_HEAP *heap, void *elem)
Definition: binaryheap.c:209
void * BH_CMP_ARG
Definition: binaryheap.h:40
#define BH_RIGHT(i)
Definition: binaryheap.c:30
bool bh_extract_max(BINARY_HEAP *heap, void *extract_elem)
Definition: binaryheap.c:304
void THREAD_ENTRY
int bh_add(BINARY_HEAP *heap, void *elem)
Definition: binaryheap.c:184
void * members
Definition: binaryheap.h:75
bool bh_is_full(BINARY_HEAP *heap)
Definition: binaryheap.c:469
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
void bh_destroy(THREAD_ENTRY *thread_p, BINARY_HEAP *heap)
Definition: binaryheap.c:157
#define BH_PARENT(i)
Definition: binaryheap.c:28
#define assert(x)
static void bh_up_heap(BINARY_HEAP *heap, int index)
Definition: binaryheap.c:56
void bh_build_heap(BINARY_HEAP *heap)
Definition: binaryheap.c:278
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
#define BH_ELEMENT_COPY(heap, dest, src)
Definition: binaryheap.c:31
BH_CMP_ARG cmp_arg
Definition: binaryheap.h:74
#define NULL
Definition: freelistheap.h:34
bool bh_peek_max(BINARY_HEAP *heap, void *peek_elem)
Definition: binaryheap.c:357
int max_capacity
Definition: binaryheap.h:69
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
bh_key_comparator cmp_func
Definition: binaryheap.h:73
#define BH_CMP(heap, l, r)
Definition: binaryheap.c:42
void * swap_buf
Definition: binaryheap.h:76
BH_HEAP_STATE state
Definition: binaryheap.h:72
BH_TRY_INSERT_RESULT
Definition: binaryheap.h:57
#define ARG_FILE_LINE
Definition: error_manager.h:44
BH_TRY_INSERT_RESULT bh_try_insert(BINARY_HEAP *heap, void *elem, void *replaced)
Definition: binaryheap.c:249
BH_CMP_RESULT(* bh_key_comparator)(const void *left, const void *right, BH_CMP_ARG arg)
Definition: binaryheap.h:64
int elem_size
Definition: binaryheap.h:70
BINARY_HEAP * bh_create(THREAD_ENTRY *thread_p, int max_capacity, int elem_size, bh_key_comparator cmp_func, BH_CMP_ARG cmp_arg)
Definition: binaryheap.c:114
int i
Definition: dynamic_load.c:954
#define BH_ELEMENT(heap, i)
Definition: binaryheap.h:79
#define BH_LEFT(i)
Definition: binaryheap.c:29