Leptonica 1.68
C Image Processing Library
|
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