Leptonica 1.68
C Image Processing Library

heap.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 /*
00017  *   heap.c
00018  *
00019  *      Create/Destroy L_Heap
00020  *          L_HEAP    *lheapCreate()
00021  *          void      *lheapDestroy()
00022  *
00023  *      Operations to add/remove to/from the heap
00024  *          l_int32    lheapAdd()
00025  *          l_int32    lheapExtendArray()
00026  *          void      *lheapRemove()
00027  *
00028  *      Heap operations
00029  *          l_int32    lheapSwapUp()
00030  *          l_int32    lheapSwapDown()
00031  *          l_int32    lheapSort()
00032  *          l_int32    lheapSortStrictOrder()
00033  *
00034  *      Accessors
00035  *          l_int32    lheapGetCount()
00036  *
00037  *      Debug output
00038  *          l_int32    lheapPrint()
00039  *
00040  *    The L_Heap is useful to implement a priority queue, that is sorted
00041  *    on a key in each element of the heap.  The heap is an array
00042  *    of nearly arbitrary structs, with a l_float32 the first field.
00043  *    This field is the key on which the heap is sorted.
00044  *
00045  *    Internally, we keep track of the heap size, n.  The item at the
00046  *    root of the heap is at the head of the array.  Items are removed
00047  *    from the head of the array and added to the end of the array.
00048  *    When an item is removed from the head, the item at the end
00049  *    of the array is moved to the head.  When items are either
00050  *    added or removed, it is usually necesary to swap array items
00051  *    to restore the heap order.  It is guaranteed that the number
00052  *    of swaps does not exceed log(n).
00053  *
00054  *    --------------------------  N.B.  ------------------------------
00055  *    The items on the heap (or, equivalently, in the array) are cast
00056  *    to void*.  Their key is a l_float32, and it is REQUIRED that the
00057  *    key be the first field in the struct.  That allows us to get the
00058  *    key by simply dereferencing the struct.  Alternatively, we could
00059  *    choose (but don't) to pass an application-specific comparison
00060  *    function into the heap operation functions.
00061  *    --------------------------  N.B.  ------------------------------
00062  */
00063 
00064 #include <stdio.h>
00065 #include <string.h>
00066 #include <stdlib.h>
00067 #include "allheaders.h"
00068 
00069 static const l_int32  MIN_BUFFER_SIZE = 20;             /* n'importe quoi */
00070 static const l_int32  INITIAL_BUFFER_ARRAYSIZE = 128;   /* n'importe quoi */
00071 
00072 #define SWAP_ITEMS(i, j)       { void *tempitem = lh->array[(i)]; \
00073                                  lh->array[(i)] = lh->array[(j)]; \
00074                                  lh->array[(j)] = tempitem; }
00075 
00076 
00077 /*--------------------------------------------------------------------------*
00078  *                          L_Heap create/destroy                           *
00079  *--------------------------------------------------------------------------*/
00080 /*!
00081  *  lheapCreate()
00082  *
00083  *      Input:  size of ptr array to be alloc'd (0 for default)
00084  *              direction (L_SORT_INCREASING, L_SORT_DECREASING)
00085  *      Return: lheap, or null on error
00086  */
00087 L_HEAP *
00088 lheapCreate(l_int32  nalloc,
00089             l_int32  direction)
00090 {
00091 L_HEAP  *lh;
00092 
00093     PROCNAME("lheapCreate");
00094 
00095     if (nalloc < MIN_BUFFER_SIZE)
00096         nalloc = MIN_BUFFER_SIZE;
00097 
00098         /* Allocate ptr array and initialize counters. */
00099     if ((lh = (L_HEAP *)CALLOC(1, sizeof(L_HEAP))) == NULL)
00100         return (L_HEAP *)ERROR_PTR("lh not made", procName, NULL);
00101     if ((lh->array = (void **)CALLOC(nalloc, sizeof(void *))) == NULL)
00102         return (L_HEAP *)ERROR_PTR("ptr array not made", procName, NULL);
00103     lh->nalloc = nalloc;
00104     lh->n = 0;
00105     lh->direction = direction;
00106     return lh;
00107 }
00108 
00109 
00110 /*!
00111  *  lheapDestroy()
00112  *
00113  *      Input:  &lheap  (<to be nulled>)
00114  *              freeflag (TRUE to free each remaining struct in the array)
00115  *      Return: void
00116  *
00117  *  Notes:
00118  *      (1) Use freeflag == TRUE when the items in the array can be
00119  *          simply destroyed using free.  If those items require their
00120  *          own destroy function, they must be destroyed before
00121  *          calling this function, and then this function is called
00122  *          with freeflag == FALSE.
00123  *      (2) To destroy the lheap, we destroy the ptr array, then
00124  *          the lheap, and then null the contents of the input ptr.
00125  */
00126 void
00127 lheapDestroy(L_HEAP  **plh,
00128              l_int32   freeflag)
00129 {
00130 l_int32  i;
00131 L_HEAP  *lh;
00132 
00133     PROCNAME("lheapDestroy");
00134 
00135     if (plh == NULL) {
00136         L_WARNING("ptr address is NULL", procName);
00137         return;
00138     }
00139     if ((lh = *plh) == NULL)
00140         return;
00141 
00142     if (freeflag) {  /* free each struct in the array */
00143         for (i = 0; i < lh->n; i++)
00144             FREE(lh->array[i]);
00145     }
00146     else if (lh->n > 0)  /* freeflag == FALSE but elements exist on array */
00147         L_WARNING_INT("memory leak of %d items in lheap!", procName, lh->n);
00148 
00149     if (lh->array)
00150         FREE(lh->array);
00151     FREE(lh);
00152     *plh = NULL;
00153 
00154     return;
00155 }
00156 
00157 /*--------------------------------------------------------------------------*
00158  *                                  Accessors                               *
00159  *--------------------------------------------------------------------------*/
00160 /*!
00161  *  lheapAdd()
00162  *
00163  *      Input:  lheap
00164  *              item to be added to the tail of the heap
00165  *      Return: 0 if OK, 1 on error
00166  */
00167 l_int32
00168 lheapAdd(L_HEAP  *lh,
00169          void    *item)
00170 {
00171     PROCNAME("lheapAdd");
00172 
00173     if (!lh)
00174         return ERROR_INT("lh not defined", procName, 1);
00175     if (!item)
00176         return ERROR_INT("item not defined", procName, 1);
00177     
00178         /* If necessary, expand the allocated array by a factor of 2 */
00179     if (lh->n >= lh->nalloc)
00180         lheapExtendArray(lh);
00181 
00182         /* Add the item */
00183     lh->array[lh->n] = item;
00184     lh->n++;
00185 
00186         /* Restore the heap */
00187     lheapSwapUp(lh, lh->n - 1);
00188     return 0;
00189 }
00190 
00191 
00192 /*!
00193  *  lheapExtendArray()
00194  *
00195  *      Input:  lheap
00196  *      Return: 0 if OK, 1 on error
00197  */
00198 l_int32
00199 lheapExtendArray(L_HEAP  *lh)
00200 {
00201     PROCNAME("lheapExtendArray");
00202 
00203     if (!lh)
00204         return ERROR_INT("lh not defined", procName, 1);
00205 
00206     if ((lh->array = (void **)reallocNew((void **)&lh->array,
00207                                 sizeof(void *) * lh->nalloc,
00208                                 2 * sizeof(void *) * lh->nalloc)) == NULL)
00209         return ERROR_INT("new ptr array not returned", procName, 1);
00210 
00211     lh->nalloc = 2 * lh->nalloc;
00212     return 0;
00213 }
00214 
00215 
00216 /*!
00217  *  lheapRemove()
00218  *
00219  *      Input:  lheap
00220  *      Return: ptr to item popped from the root of the heap,
00221  *              or null if the heap is empty or on error
00222  */
00223 void *
00224 lheapRemove(L_HEAP  *lh)
00225 {
00226 void   *item;
00227 
00228     PROCNAME("lheapRemove");
00229 
00230     if (!lh)
00231         return (void *)ERROR_PTR("lh not defined", procName, NULL);
00232 
00233     if (lh->n == 0)
00234         return NULL;
00235 
00236     item = lh->array[0];
00237     lh->array[0] = lh->array[lh->n - 1];  /* move last to the head */
00238     lh->array[lh->n - 1] = NULL;  /* set ptr to null */
00239     lh->n--;
00240 
00241     lheapSwapDown(lh);  /* restore the heap */
00242     return item;
00243 }
00244        
00245 
00246 /*!
00247  *  lheapGetCount()
00248  *
00249  *      Input:  lheap
00250  *      Return: count, or 0 on error
00251  */
00252 l_int32
00253 lheapGetCount(L_HEAP  *lh)
00254 {
00255     PROCNAME("lheapGetCount");
00256 
00257     if (!lh)
00258         return ERROR_INT("lh not defined", procName, 0);
00259 
00260     return lh->n;
00261 }
00262         
00263 
00264 
00265 /*--------------------------------------------------------------------------*
00266  *                               Heap operations                            *
00267  *--------------------------------------------------------------------------*/
00268 /*!
00269  *  lheapSwapUp()
00270  *
00271  *      Input:  lh (heap)
00272  *              index (of array corresponding to node to be swapped up)
00273  *      Return: 0 if OK, 1 on error
00274  *
00275  *  Notes:
00276  *      (1) This is called after a new item is put on the heap, at the
00277  *          bottom of a complete tree.
00278  *      (2) To regain the heap order, we let it bubble up,
00279  *          iteratively swapping with its parent, until it either
00280  *          reaches the root of the heap or it finds a parent that
00281  *          is in the correct position already vis-a-vis the child.
00282  */
00283 l_int32
00284 lheapSwapUp(L_HEAP  *lh,
00285             l_int32  index)
00286 {
00287 l_int32    ip;  /* index to heap for parent; 1 larger than array index */
00288 l_int32    ic;  /* index into heap for child */
00289 l_float32  valp, valc;
00290 
00291   PROCNAME("lheapSwapUp");
00292 
00293   if (!lh)
00294       return ERROR_INT("lh not defined", procName, 1);
00295   if (index < 0 || index >= lh->n)
00296       return ERROR_INT("invalid index", procName, 1);
00297 
00298   ic = index + 1;  /* index into heap: add 1 to array index */
00299   if (lh->direction == L_SORT_INCREASING) {
00300       while (1) {
00301           if (ic == 1)  /* root of heap */
00302               break;
00303           ip = ic / 2;
00304           valc = *(l_float32 *)(lh->array[ic - 1]);
00305           valp = *(l_float32 *)(lh->array[ip - 1]);
00306           if (valp <= valc)
00307              break;
00308           SWAP_ITEMS(ip - 1, ic - 1);
00309           ic = ip;
00310       }
00311   }
00312   else {  /* lh->direction == L_SORT_DECREASING */
00313       while (1) {
00314           if (ic == 1)  /* root of heap */
00315               break;
00316           ip = ic / 2;
00317           valc = *(l_float32 *)(lh->array[ic - 1]);
00318           valp = *(l_float32 *)(lh->array[ip - 1]);
00319           if (valp >= valc)
00320              break;
00321           SWAP_ITEMS(ip - 1, ic - 1);
00322           ic = ip;
00323       }
00324   }
00325   return 0;
00326 }
00327 
00328 
00329 /*!
00330  *  lheapSwapDown()
00331  *
00332  *      Input:  lh (heap)
00333  *      Return: 0 if OK, 1 on error
00334  *
00335  *  Notes:
00336  *      (1) This is called after an item has been popped off the
00337  *          root of the heap, and the last item in the heap has
00338  *          been placed at the root.
00339  *      (2) To regain the heap order, we let it bubble down,
00340  *          iteratively swapping with one of its children.  For a
00341  *          decreasing sort, it swaps with the largest child; for
00342  *          an increasing sort, the smallest.  This continues until
00343  *          it either reaches the lowest level in the heap, or the
00344  *          parent finds that neither child should swap with it
00345  *          (e.g., for a decreasing heap, the parent is larger
00346  *          than or equal to both children).
00347  */
00348 l_int32
00349 lheapSwapDown(L_HEAP  *lh)
00350 {
00351 l_int32    ip;  /* index to heap for parent; 1 larger than array index */
00352 l_int32    icr, icl;  /* index into heap for left/right children */
00353 l_float32  valp, valcl, valcr;
00354 
00355   PROCNAME("lheapSwapDown");
00356 
00357   if (!lh)
00358       return ERROR_INT("lh not defined", procName, 1);
00359   if (lheapGetCount(lh) < 1)
00360       return 0;
00361 
00362   ip = 1;  /* index into top of heap: corresponds to array[0] */
00363   if (lh->direction == L_SORT_INCREASING) {
00364       while (1) {
00365           icl = 2 * ip;
00366           if (icl > lh->n)
00367              break;
00368           valp = *(l_float32 *)(lh->array[ip - 1]);
00369           valcl = *(l_float32 *)(lh->array[icl - 1]);
00370           icr = icl + 1;
00371           if (icr > lh->n) {  /* only a left child; no iters below */
00372               if (valp > valcl)
00373                   SWAP_ITEMS(ip - 1, icl - 1);
00374               break;
00375           }
00376           else {  /* both children present; swap with the smallest if bigger */
00377               valcr = *(l_float32 *)(lh->array[icr - 1]);
00378               if (valp <= valcl && valp <= valcr)  /* smaller than both */
00379                   break;
00380               if (valcl <= valcr) {  /* left smaller; swap */
00381                   SWAP_ITEMS(ip - 1, icl - 1);
00382                   ip = icl;
00383               }
00384               else { /* right smaller; swap */
00385                   SWAP_ITEMS(ip - 1, icr - 1);
00386                   ip = icr;
00387               }
00388           }
00389       }
00390   }
00391   else {  /* lh->direction == L_SORT_DECREASING */
00392       while (1) {
00393           icl = 2 * ip;
00394           if (icl > lh->n)
00395              break;
00396           valp = *(l_float32 *)(lh->array[ip - 1]);
00397           valcl = *(l_float32 *)(lh->array[icl - 1]);
00398           icr = icl + 1;
00399           if (icr > lh->n) {  /* only a left child; no iters below */
00400               if (valp < valcl)
00401                   SWAP_ITEMS(ip - 1, icl - 1);
00402               break;
00403           }
00404           else {  /* both children present; swap with the biggest if smaller */
00405               valcr = *(l_float32 *)(lh->array[icr - 1]);
00406               if (valp >= valcl && valp >= valcr)  /* bigger than both */
00407                   break;
00408               if (valcl >= valcr) {  /* left bigger; swap */
00409                   SWAP_ITEMS(ip - 1, icl - 1);
00410                   ip = icl;
00411               }
00412               else { /* right bigger; swap */
00413                   SWAP_ITEMS(ip - 1, icr - 1);
00414                   ip = icr;
00415               }
00416           }
00417       }
00418   }
00419 
00420   return 0;
00421 }
00422 
00423 
00424 /*!
00425  *  lheapSort()
00426  *
00427  *      Input:  lh (heap, with internal array)
00428  *      Return: 0 if OK, 1 on error
00429  *
00430  *  Notes:
00431  *      (1) This sorts an array into heap order.  If the heap is already
00432  *          in heap order for the direction given, this has no effect.
00433  */
00434 l_int32
00435 lheapSort(L_HEAP  *lh)
00436 {
00437 l_int32  i;
00438 
00439   PROCNAME("lheapSort");
00440 
00441   if (!lh)
00442       return ERROR_INT("lh not defined", procName, 1);
00443 
00444   for (i = 0; i < lh->n; i++)
00445       lheapSwapUp(lh, i);
00446 
00447   return 0;
00448 }
00449 
00450 
00451 /*!
00452  *  lheapSortStrictOrder()
00453  *
00454  *      Input:  lh (heap, with internal array)
00455  *      Return: 0 if OK, 1 on error
00456  *
00457  *  Notes:
00458  *      (1) This sorts a heap into strict order.
00459  *      (2) For each element, starting at the end of the array and
00460  *          working forward, the element is swapped with the head
00461  *          element and then allowed to swap down onto a heap of
00462  *          size reduced by one.  The result is that the heap is
00463  *          reversed but in strict order.  The array elements are
00464  *          then reversed to put it in the original order.
00465  */
00466 l_int32
00467 lheapSortStrictOrder(L_HEAP  *lh)
00468 {
00469 l_int32  i, index, size;
00470 
00471   PROCNAME("lheapSortStrictOrder");
00472 
00473   if (!lh)
00474       return ERROR_INT("lh not defined", procName, 1);
00475 
00476   size = lh->n;  /* save the actual size */
00477   for (i = 0; i < size; i++) {
00478       index = size - i;
00479       SWAP_ITEMS(0, index - 1);
00480       lh->n--;  /* reduce the apparent heap size by 1 */
00481       lheapSwapDown(lh);
00482   }
00483   lh->n = size;  /* restore the size */
00484 
00485   for (i = 0; i < size / 2; i++)  /* reverse */
00486       SWAP_ITEMS(i, size - i - 1);
00487 
00488   return 0;
00489 }
00490 
00491 
00492 
00493 /*---------------------------------------------------------------------*
00494  *                            Debug output                             *
00495  *---------------------------------------------------------------------*/
00496 /*!
00497  *  lheapPrint()
00498  *  
00499  *      Input:  stream
00500  *              lheap
00501  *      Return: 0 if OK; 1 on error
00502  */
00503 l_int32
00504 lheapPrint(FILE    *fp,
00505            L_HEAP  *lh)
00506 {
00507 l_int32  i;
00508 
00509     PROCNAME("lheapPrint");
00510 
00511     if (!fp)
00512         return ERROR_INT("stream not defined", procName, 1);
00513     if (!lh)
00514         return ERROR_INT("lh not defined", procName, 1);
00515 
00516     fprintf(fp, "\n L_Heap: nalloc = %d, n = %d, array = %p\n",
00517             lh->nalloc, lh->n, lh->array);
00518     for (i = 0; i < lh->n; i++)
00519         fprintf(fp,   "keyval[%d] = %f\n", i, *(l_float32 *)lh->array[i]);
00520 
00521     return 0;
00522 }
00523 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines