| /** @file heap-def.h | |
| ** @brief Heap preprocessor metaprogram | |
| ** @author Andrea Vedaldi | |
| **/ | |
| /* | |
| Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. | |
| All rights reserved. | |
| This file is part of the VLFeat library and is made available under | |
| the terms of the BSD license (see the COPYING file). | |
| */ | |
| /** @file heap-def.h | |
| A heap organizes an array of objects in a priority queue. This module | |
| is a template metaprogram that defines heap operations on array of | |
| generic objects, or even generic object containers. | |
| - @ref heap-def-overview "Overview" | |
| - @ref heap-def-overview-general "General usage" | |
| - @ref heap-def-tech "Technical details" | |
| <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> | |
| @section heap-def-overview Overview | |
| <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> | |
| To use @ref heap-def.h one must specify at least a prefix and the data | |
| type for the heap elements: | |
| @code | |
| #define VL_HEAP_prefix my_heap | |
| #define VL_HEAP_type float | |
| #include <vl/heap-def.h> | |
| @endcode | |
| This code fragment defines a number of functions prefixed by | |
| ::VL_HEAP_prefix, such as @c my_heap_push (::VL_HEAP_push) and @c | |
| my_heap_pop (::VL_HEAP_pop), that implement the heap operations. | |
| These functions operate on an array that has type ::VL_HEAP_array. | |
| By default, this is defined to be: | |
| @code | |
| #define VL_HEAP_array VL_HEAP_type* | |
| #define VL_HEAP_array_const VL_HEAP_type const* | |
| @endcode | |
| The array itself is accessed uniquely by means of two functions: | |
| - ::VL_HEAP_cmp, that compares two array elements. The default | |
| implementation assumes that ::VL_HEAP_type is numeric. | |
| - ::VL_HEAP_swap, that swaps two array elements. The default | |
| implementation assumes that ::VL_HEAP_type can be copied by the @c | |
| = operator. | |
| The heap state is a integer @c numElements (of type ::vl_size) counting | |
| the number of elements of the array that are currently part of the heap | |
| and the content of the first @c numElements elements of the array. The | |
| portion of the array that constitutes the heap satisfies a certain | |
| invariant property (heap property, @ref heap-def-tech). From a user | |
| viewpoint, the most important consequence is that the first element | |
| of the array (the one of index 0) is also the smallest (according to | |
| ::VL_HEAP_cmp). | |
| Elements are added to the heap by ::VL_HEAP_push and removed from the | |
| heap by ::VL_HEAP_pop. A push operation adds to the heap the array | |
| element immediately after the last element already in the heap | |
| (i.e. the element of index @c numElements) and increases the number of | |
| heap elements @c numElements. Elements in the heap are swapped as required in | |
| order to maintain the heap consistency. Similarly, a pop operation | |
| removes the first (smaller) element from the heap and decreases the | |
| number of heap elements @c numElements. | |
| The values of nodes currently in the heap can be updated by | |
| ::VL_HEAP_update. Notice however that using this function requires | |
| knowing the index of the element that needs to be updated up to the | |
| swapping operations that the heap performs to maintain | |
| consistency. Typically, this requires redefining ::VL_HEAP_swap to | |
| keep track of such changes (@ref heap-def-overview-general). | |
| <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> | |
| @subsection heap-def-overview-general General usage | |
| <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> | |
| The heap container may be mapped to any type by reimplementing | |
| ::VL_HEAP_cmp and ::VL_HEAP_swap explicitly. For instance | |
| the following code redefines ::VL_HEAP_cmp to deal with the case | |
| in which the heap is an array of structures: | |
| @code | |
| typedef struct _S { int x ; } S ; | |
| int s_cmp (S const * v, vl_uindex a, vl_uindex b) { | |
| return v[a].x - v[b].x ; | |
| } | |
| #define VL_HEAP_prefix s_heap | |
| #define VL_HEAP_type S | |
| #define VL_HEAP_cmp s_cmp | |
| #include <vl/heap-def.h> | |
| @endcode | |
| In the following example, the heap itself is an arbitrary structure: | |
| @code | |
| typedef struct _H { int* array ; } H ; | |
| int h_cmp (H const * h, vl_uindex a, vl_uindex b) { | |
| return h->array[a] - h->array[b] ; | |
| } | |
| int h_swap (H * h, vl_uindex a, vl_uindex b) { | |
| int t = h->array[a] ; | |
| h->array[a] = h->array[b] ; | |
| h->array[b] = t ; | |
| } | |
| #define VL_HEAP_prefix h_heap | |
| #define VL_HEAP_swap h_swap | |
| #define VL_HEAP_cmp h_cmp | |
| #include <vl/heap-def.h> | |
| @endcode | |
| <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> | |
| @section heap-def-tech Technical details | |
| <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> | |
| The heap is organised as a binary tree with the property (<em>heap | |
| property</em>) that any node is not larger than any of its | |
| children. In particular, the root is the smallest node. | |
| @ref heap-def.h uses the standard binary tree representation as a linear | |
| array. Tree nodes are mapped to array elements as follows: | |
| <code>array[0]</code> corresponds to the root, <code>array[1]</code> | |
| and <code>array[2]</code> to the root left and right children and so | |
| on. In this way, the tree structure is fully specified by the total | |
| number of nodes <code>N</code>. | |
| Assuming that the heap has <code>N</code> nodes (from | |
| <code>array[0]</code> to <code>array[N-1]</code>), adding the node | |
| <code>array[N]</code> to the heap is done by a <em>push down</em> | |
| operation: if the node <code>array[N]</code> is smaller than its | |
| parent (violating the heap property) it is pushed down by swapping it | |
| with the parent, and so on recursively. | |
| Removing the smallest element <code>array[0]</code> with an heap of | |
| <code>N</code> nodes is done by swapping <code>array[0]</code> with | |
| <code>array[N-1]</code>. If then <code>array[0]</code> is larger than | |
| any of its children, it is swapped with the smallest of the two and | |
| so on recursively (<em>push up</em> operation). | |
| Restoring the heap property after an element <code>array[i]</code> | |
| has been modified can be done by a push up or push down operation on | |
| that node. | |
| **/ | |
| /* ---------------------------------------------------------------- */ | |
| /** @internal @brief Get index of parent node | |
| ** @param index a node index. | |
| ** @return index of the parent node. | |
| **/ | |
| VL_INLINE vl_uindex | |
| vl_heap_parent (vl_uindex index) | |
| { | |
| if (index == 0) return 0 ; | |
| return (index - 1) / 2 ; | |
| } | |
| /** @internal @brief Get index of left child | |
| ** @param index a node index. | |
| ** @return index of the left child. | |
| **/ | |
| VL_INLINE vl_uindex | |
| vl_heap_left_child (vl_uindex index) | |
| { | |
| return 2 * index + 1 ; | |
| } | |
| /** @internal @brief Get index of right child | |
| ** @param index a node index. | |
| ** @return index of the right child. | |
| **/ | |
| VL_INLINE vl_uindex | |
| vl_heap_right_child (vl_uindex index) | |
| { | |
| return vl_heap_left_child (index) + 1 ; | |
| } | |
| /* VL_HEAP_DEF_H */ | |
| /* ---------------------------------------------------------------- */ | |
| /** @brief Compare two heap elements | |
| ** @param array heap array. | |
| ** @param indexA index of the first element @c A to compare. | |
| ** @param indexB index of the second element @c B to comapre. | |
| ** @return a negative number if @c A<B, 0 if @c A==B, and | |
| ** a positive number if if @c A>B. | |
| **/ | |
| VL_INLINE VL_HEAP_type | |
| VL_HEAP_cmp | |
| (VL_HEAP_array_const array, | |
| vl_uindex indexA, | |
| vl_uindex indexB) | |
| { | |
| return array[indexA] - array[indexB] ; | |
| } | |
| /* VL_HEAP_cmp */ | |
| /* ---------------------------------------------------------------- */ | |
| /** @brief Swap two heap elements | |
| ** @param array array of nodes. | |
| ** @param array heap array. | |
| ** @param indexA index of the first node to swap. | |
| ** @param indexB index of the second node to swap. | |
| ** | |
| ** The function swaps the two heap elements @a a and @ b. The function | |
| ** uses a temporary element and the copy operator, which must be | |
| ** well defined for the heap elements. | |
| **/ | |
| VL_INLINE void | |
| VL_HEAP_swap | |
| (VL_HEAP_array array, | |
| vl_uindex indexA, | |
| vl_uindex indexB) | |
| { | |
| VL_HEAP_type t = array [indexA] ; | |
| array [indexA] = array [indexB] ; | |
| array [indexB] = t ; | |
| } | |
| /* VL_HEAP_swap */ | |
| /* ---------------------------------------------------------------- */ | |
| /** @brief Heap up operation | |
| ** @param array pointer to the heap array. | |
| ** @param heapSize size of the heap. | |
| ** @param index index of the node to push up. | |
| **/ | |
| VL_INLINE void | |
| VL_HEAP_up | |
| (VL_HEAP_array array, vl_size heapSize, vl_uindex index) | |
| { | |
| vl_uindex leftIndex = vl_heap_left_child (index) ; | |
| vl_uindex rightIndex = vl_heap_right_child (index) ; | |
| /* no childer: stop */ | |
| if (leftIndex >= heapSize) return ; | |
| /* only left childer: easy */ | |
| if (rightIndex >= heapSize) { | |
| if (VL_HEAP_cmp (array, index, leftIndex) > 0) { | |
| VL_HEAP_swap (array, index, leftIndex) ; | |
| } | |
| return ; | |
| } | |
| /* both childern */ | |
| { | |
| if (VL_HEAP_cmp (array, leftIndex, rightIndex) < 0) { | |
| /* swap with left */ | |
| if (VL_HEAP_cmp (array, index, leftIndex) > 0) { | |
| VL_HEAP_swap (array, index, leftIndex) ; | |
| VL_HEAP_up (array, heapSize, leftIndex) ; | |
| } | |
| } else { | |
| /* swap with right */ | |
| if (VL_HEAP_cmp (array, index, rightIndex) > 0) { | |
| VL_HEAP_swap (array, index, rightIndex) ; | |
| VL_HEAP_up (array, heapSize, rightIndex) ; | |
| } | |
| } | |
| } | |
| } | |
| /* VL_HEAP_up */ | |
| /* ---------------------------------------------------------------- */ | |
| /** @brief Heap down operation | |
| ** @param array pointer to the heap node array. | |
| ** @param index index of the node to push up. | |
| **/ | |
| VL_INLINE void | |
| VL_HEAP_down | |
| (VL_HEAP_array array, vl_uindex index) | |
| { | |
| vl_uindex parentIndex ; | |
| if (index == 0) return ; | |
| parentIndex = vl_heap_parent (index) ; | |
| if (VL_HEAP_cmp (array, index, parentIndex) < 0) { | |
| VL_HEAP_swap (array, index, parentIndex) ; | |
| VL_HEAP_down (array, parentIndex) ; | |
| } | |
| } | |
| /* VL_HEAP_down */ | |
| /* ---------------------------------------------------------------- */ | |
| /** @brief Heap push operation | |
| ** @param array pointer to the heap array. | |
| ** @param heapSize (in/out) size of the heap. | |
| ** | |
| ** The function adds to the heap the element of index @c heapSize | |
| ** and increments @c heapSize. | |
| **/ | |
| VL_INLINE void | |
| VL_HEAP_push | |
| (VL_HEAP_array array, vl_size *heapSize) | |
| { | |
| VL_HEAP_down (array, *heapSize) ; | |
| *heapSize += 1 ; | |
| } | |
| /* VL_HEAP_push */ | |
| /* ---------------------------------------------------------------- */ | |
| /** @brief Heap pop operation | |
| ** @param array pointer to the heap array. | |
| ** @param heapSize (in/out) size of the heap. | |
| ** @return index of the popped element. | |
| ** | |
| ** The function extracts from the heap the element of index 0 | |
| ** (the smallest element) and decreases @c heapSize. | |
| ** | |
| ** The element extracted is moved as the first element after | |
| ** the heap end (thus it has index @c heapSize). For convenience, | |
| ** this index is returned by the function. | |
| ** | |
| ** Popping from an empty heap is undefined. | |
| **/ | |
| VL_INLINE vl_uindex | |
| VL_HEAP_pop | |
| (VL_HEAP_array array, vl_size *heapSize) | |
| { | |
| assert (*heapSize) ; | |
| *heapSize -= 1 ; | |
| VL_HEAP_swap (array, 0, *heapSize) ; | |
| if (*heapSize > 1) { | |
| VL_HEAP_up (array, *heapSize, 0) ; | |
| } | |
| return *heapSize ; | |
| } | |
| /* VL_HEAP_pop */ | |
| /* ---------------------------------------------------------------- */ | |
| /** @brief Heap update operation | |
| ** @param array pointer to the heap array. | |
| ** @param heapSize size of the heap. | |
| ** @param index index of the node to update. | |
| ** | |
| ** The function updates the heap to account for a change to the | |
| ** element of index @c index in the heap. | |
| ** | |
| ** Notice that using this | |
| ** function requires knowing the index of the heap index of | |
| ** element that was changed. Since the heap swaps elements in the | |
| ** array, this is in general different from the index that that | |
| ** element had originally. | |
| **/ | |
| VL_INLINE void | |
| VL_HEAP_update | |
| (VL_HEAP_array array, | |
| vl_size heapSize, | |
| vl_uindex index) | |
| { | |
| VL_HEAP_up (array, heapSize, index) ; | |
| VL_HEAP_down (array, index) ; | |
| } | |
| /* VL_HEAP_update */ | |
| /* ---------------------------------------------------------------- */ | |