heap.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2007, 2010-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1997-2001  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file
00021  * Heap implementation of priority queues adapted from the following:
00022  *
00023  *      \li "Introduction to Algorithms," Cormen, Leiserson, and Rivest,
00024  *      MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7.
00025  *
00026  *      \li "Algorithms," Second Edition, Sedgewick, Addison-Wesley, 1988,
00027  *      ISBN 0-201-06673-4, chapter 11.
00028  */
00029 
00030 #include <config.h>
00031 
00032 #include <isc/heap.h>
00033 #include <isc/magic.h>
00034 #include <isc/mem.h>
00035 #include <isc/string.h>         /* Required for memmove. */
00036 #include <isc/util.h>
00037 
00038 /*@{*/
00039 /*%
00040  * Note: to make heap_parent and heap_left easy to compute, the first
00041  * element of the heap array is not used; i.e. heap subscripts are 1-based,
00042  * not 0-based.  The parent is index/2, and the left-child is index*2.
00043  * The right child is index*2+1.
00044  */
00045 #define heap_parent(i)                  ((i) >> 1)
00046 #define heap_left(i)                    ((i) << 1)
00047 /*@}*/
00048 
00049 #define SIZE_INCREMENT                  1024
00050 
00051 #define HEAP_MAGIC                      ISC_MAGIC('H', 'E', 'A', 'P')
00052 #define VALID_HEAP(h)                   ISC_MAGIC_VALID(h, HEAP_MAGIC)
00053 
00054 /*%
00055  * When the heap is in a consistent state, the following invariant
00056  * holds true: for every element i > 1, heap_parent(i) has a priority
00057  * higher than or equal to that of i.
00058  */
00059 #define HEAPCONDITION(i) ((i) == 1 || \
00060                           ! heap->compare(heap->array[(i)], \
00061                                           heap->array[heap_parent(i)]))
00062 
00063 /*% ISC heap structure. */
00064 struct isc_heap {
00065         unsigned int                    magic;
00066         isc_mem_t *                     mctx;
00067         unsigned int                    size;
00068         unsigned int                    size_increment;
00069         unsigned int                    last;
00070         void                            **array;
00071         isc_heapcompare_t               compare;
00072         isc_heapindex_t                 index;
00073 };
00074 
00075 isc_result_t
00076 isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare,
00077                 isc_heapindex_t idx, unsigned int size_increment,
00078                 isc_heap_t **heapp)
00079 {
00080         isc_heap_t *heap;
00081 
00082         REQUIRE(heapp != NULL && *heapp == NULL);
00083         REQUIRE(compare != NULL);
00084 
00085         heap = isc_mem_get(mctx, sizeof(*heap));
00086         if (heap == NULL)
00087                 return (ISC_R_NOMEMORY);
00088         heap->magic = HEAP_MAGIC;
00089         heap->size = 0;
00090         heap->mctx = NULL;
00091         isc_mem_attach(mctx, &heap->mctx);
00092         if (size_increment == 0)
00093                 heap->size_increment = SIZE_INCREMENT;
00094         else
00095                 heap->size_increment = size_increment;
00096         heap->last = 0;
00097         heap->array = NULL;
00098         heap->compare = compare;
00099         heap->index = idx;
00100 
00101         *heapp = heap;
00102 
00103         return (ISC_R_SUCCESS);
00104 }
00105 
00106 void
00107 isc_heap_destroy(isc_heap_t **heapp) {
00108         isc_heap_t *heap;
00109 
00110         REQUIRE(heapp != NULL);
00111         heap = *heapp;
00112         REQUIRE(VALID_HEAP(heap));
00113 
00114         if (heap->array != NULL)
00115                 isc_mem_put(heap->mctx, heap->array,
00116                             heap->size * sizeof(void *));
00117         heap->magic = 0;
00118         isc_mem_putanddetach(&heap->mctx, heap, sizeof(*heap));
00119 
00120         *heapp = NULL;
00121 }
00122 
00123 static isc_boolean_t
00124 resize(isc_heap_t *heap) {
00125         void **new_array;
00126         unsigned int new_size;
00127 
00128         REQUIRE(VALID_HEAP(heap));
00129 
00130         new_size = heap->size + heap->size_increment;
00131         new_array = isc_mem_get(heap->mctx, new_size * sizeof(void *));
00132         if (new_array == NULL)
00133                 return (ISC_FALSE);
00134         if (heap->array != NULL) {
00135                 memmove(new_array, heap->array, heap->size * sizeof(void *));
00136                 isc_mem_put(heap->mctx, heap->array,
00137                             heap->size * sizeof(void *));
00138         }
00139         heap->size = new_size;
00140         heap->array = new_array;
00141 
00142         return (ISC_TRUE);
00143 }
00144 
00145 static void
00146 float_up(isc_heap_t *heap, unsigned int i, void *elt) {
00147         unsigned int p;
00148 
00149         for (p = heap_parent(i) ;
00150              i > 1 && heap->compare(elt, heap->array[p]) ;
00151              i = p, p = heap_parent(i)) {
00152                 heap->array[i] = heap->array[p];
00153                 if (heap->index != NULL)
00154                         (heap->index)(heap->array[i], i);
00155         }
00156         heap->array[i] = elt;
00157         if (heap->index != NULL)
00158                 (heap->index)(heap->array[i], i);
00159 
00160         INSIST(HEAPCONDITION(i));
00161 }
00162 
00163 static void
00164 sink_down(isc_heap_t *heap, unsigned int i, void *elt) {
00165         unsigned int j, size, half_size;
00166         size = heap->last;
00167         half_size = size / 2;
00168         while (i <= half_size) {
00169                 /* Find the smallest of the (at most) two children. */
00170                 j = heap_left(i);
00171                 if (j < size && heap->compare(heap->array[j+1],
00172                                               heap->array[j]))
00173                         j++;
00174                 if (heap->compare(elt, heap->array[j]))
00175                         break;
00176                 heap->array[i] = heap->array[j];
00177                 if (heap->index != NULL)
00178                         (heap->index)(heap->array[i], i);
00179                 i = j;
00180         }
00181         heap->array[i] = elt;
00182         if (heap->index != NULL)
00183                 (heap->index)(heap->array[i], i);
00184 
00185         INSIST(HEAPCONDITION(i));
00186 }
00187 
00188 isc_result_t
00189 isc_heap_insert(isc_heap_t *heap, void *elt) {
00190         unsigned int new_last;
00191 
00192         REQUIRE(VALID_HEAP(heap));
00193 
00194         new_last = heap->last + 1;
00195         RUNTIME_CHECK(new_last > 0); /* overflow check */
00196         if (new_last >= heap->size && !resize(heap))
00197                 return (ISC_R_NOMEMORY);
00198         heap->last = new_last;
00199 
00200         float_up(heap, new_last, elt);
00201 
00202         return (ISC_R_SUCCESS);
00203 }
00204 
00205 void
00206 isc_heap_delete(isc_heap_t *heap, unsigned int idx) {
00207         void *elt;
00208         isc_boolean_t less;
00209 
00210         REQUIRE(VALID_HEAP(heap));
00211         REQUIRE(idx >= 1 && idx <= heap->last);
00212 
00213         if (idx == heap->last) {
00214                 heap->array[heap->last] = NULL;
00215                 heap->last--;
00216         } else {
00217                 elt = heap->array[heap->last];
00218                 heap->array[heap->last] = NULL;
00219                 heap->last--;
00220 
00221                 less = heap->compare(elt, heap->array[idx]);
00222                 heap->array[idx] = elt;
00223                 if (less)
00224                         float_up(heap, idx, heap->array[idx]);
00225                 else
00226                         sink_down(heap, idx, heap->array[idx]);
00227         }
00228 }
00229 
00230 void
00231 isc_heap_increased(isc_heap_t *heap, unsigned int idx) {
00232         REQUIRE(VALID_HEAP(heap));
00233         REQUIRE(idx >= 1 && idx <= heap->last);
00234 
00235         float_up(heap, idx, heap->array[idx]);
00236 }
00237 
00238 void
00239 isc_heap_decreased(isc_heap_t *heap, unsigned int idx) {
00240         REQUIRE(VALID_HEAP(heap));
00241         REQUIRE(idx >= 1 && idx <= heap->last);
00242 
00243         sink_down(heap, idx, heap->array[idx]);
00244 }
00245 
00246 void *
00247 isc_heap_element(isc_heap_t *heap, unsigned int idx) {
00248         REQUIRE(VALID_HEAP(heap));
00249         REQUIRE(idx >= 1);
00250 
00251         if (idx <= heap->last)
00252                 return (heap->array[idx]);
00253         return (NULL);
00254 }
00255 
00256 void
00257 isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap) {
00258         unsigned int i;
00259 
00260         REQUIRE(VALID_HEAP(heap));
00261         REQUIRE(action != NULL);
00262 
00263         for (i = 1 ; i <= heap->last ; i++)
00264                 (action)(heap->array[i], uap);
00265 }

Generated on Tue Apr 28 17:41:04 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha