00001 /* EGlib "Efficient General Library" provides some basic structures and 00002 * algorithms commons in many optimization algorithms. 00003 * 00004 * Copyright (C) 2005 Daniel Espinoza and Marcos Goycoolea. 00005 * 00006 * This library is free software; you can redistribute it and/or modify it 00007 * under the terms of the GNU Lesser General Public License as published by the 00008 * Free Software Foundation; either version 2.1 of the License, or (at your 00009 * option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, but 00012 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 00013 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 00014 * License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this library; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00019 * */ 00020 /* ========================================================================= */ 00021 /** @defgroup EGeHeap EGeHeap 00022 * 00023 * Here we define the basic interface for d-heaps as an embeded structure. 00024 * In this implementation the heap does not grow on the fly, meaning that it 00025 * may fills-up during an add call, to avoid that, the user must call 00026 * re-allocate when necesary. the heap start as a heap of size zero. 00027 * This implementatioon is a minimum-heap implementatiton. Note also that the 00028 * internal connector array is shifted one position to the left. This is done 00029 * so that the first element is in position 1, this also speed-up the 00030 * computation of the parent and childrens of a given position. 00031 * 00032 * @version 0.0.1 00033 * @par History: 00034 * - 2005-07-14 00035 * - Add EGeHeapEmpty to empty the heap (but keep its maximum 00036 * size) 00037 * - Add EGeHeapIsFull to test wether a heap is full or not. 00038 * - 2005-07-07 00039 * - First Implementation 00040 * @note 00041 * This implementatiton is designed as a template using as base the types of 00042 * @ref EGlpNum 00043 * */ 00044 /** @file 00045 * @ingroup EGeHeap */ 00046 /** @addtogroup EGeHeap */ 00047 /** @{ */ 00048 /** @example eg_eheap.ex.c 00049 * This is a simple example of the usage of heaps using @ref EGeHeap */ 00050 /* ========================================================================= */ 00051 #ifndef __EG_EHEAP__ 00052 #define __EG_EHEAP__ 00053 #include <stdlib.h> 00054 #include <stdio.h> 00055 #include <string.h> 00056 #include <limits.h> 00057 #include <float.h> 00058 #include "eg_macros.h" 00059 #include "eg_lpnum.h" 00060 /* ========================================================================= */ 00061 /** @brief Debug level for the heap */ 00062 #define EG_EHEAP_DEBUG 1000 00063 00064 /* ========================================================================= */ 00065 /** @brief Structure to store the information relevant to an element in the 00066 * heap. */ 00067 typedef struct EGeHeapCn_t 00068 { 00069 EGlpNum_t val; /**< Value of this node in the heap */ 00070 unsigned int pos; /**< Position in the heap array for this node, if set to 00071 #EG_EHEAP_POISON, then the connector is not in any 00072 heap.*/ 00073 } 00074 EGeHeapCn_t; 00075 00076 /* ========================================================================= */ 00077 /** @brief Poison position for heap connector not in a heap. */ 00078 #define EG_EHEAP_POISON UINT_MAX 00079 00080 /* ========================================================================= */ 00081 /** @brief Initialize a heap conector structure. This function will allocate any 00082 * interal memory not allocated by the user, it should be called only once, or 00083 * after a clear function call. 00084 * @param hcn conector to initialize. 00085 * */ 00086 #define EGeHeapCnInit(hcn) ({EGlpNumInitVar((hcn)->val);(hcn)->pos = EG_EHEAP_POISON;}) 00087 00088 /* ========================================================================= */ 00089 /** @brief Reset a heap conector to the same state as after an init call, this 00090 * function is provided only for completness. 00091 * @param hcn conector to reset 00092 * */ 00093 #define EGeHeapCnReset(hcn) ((hcn)->pos = EG_EHEAP_POISON) 00094 00095 /* ========================================================================= */ 00096 /** @brief Free all internal memory used by this structured not allocated by the 00097 * user. This function should be called after an init call, and only once. 00098 * @param hcn conector to clear. 00099 * */ 00100 #define EGeHeapCnClear(hcn) EGlpNumClearVar((hcn)->val) 00101 00102 /* ========================================================================= */ 00103 /** @brief Structure to hold a whole heap structure, this structure is designed 00104 * so that it can grow on the fly with a low cost */ 00105 typedef struct EGeHeap_t 00106 { 00107 EGeHeapCn_t **cn; 00108 unsigned int d; 00109 unsigned int sz; 00110 unsigned int max_sz; 00111 } 00112 EGeHeap_t; 00113 00114 /* ========================================================================= */ 00115 /** @brief Return one if the heap is full, zero otherwise. 00116 * @param hp heat to check */ 00117 #define EGeHeapIsFull(hp) ({EGeHeap_t*const __EGehp = (hp); __EGehp->sz == __EGehp->max_sz;}) 00118 00119 /* ========================================================================= */ 00120 /** @brief set the number of elements in hte heap to zero. 00121 * @param hp heap to empty. 00122 * */ 00123 #define EGeHeapEmpty(hp) ((hp)->sz = 0) 00124 00125 /* ========================================================================= */ 00126 /** @brief Initialize a heap as an empty heap (with no space for conectors). 00127 * @param hp heap to initialize. 00128 * */ 00129 #define EGeHeapInit(hp) (*(hp) = (EGeHeap_t){0,0,0,0}) 00130 00131 /* ========================================================================= */ 00132 /** @brief Reset the given heap as an empty heap (just as returned by the init 00133 * call. 00134 * @param hp heap to reset 00135 * */ 00136 #define EGeHepReset(hp) EGeHeapInit(hp) 00137 00138 /* ========================================================================= */ 00139 /** @brief Clear a heap structure, and free any internal memory (not allocated 00140 * by the user). 00141 * @param hp heap to clear. 00142 * */ 00143 #define EGeHeapClear(hp) 00144 00145 /* ========================================================================= */ 00146 /** @brief get the minimum value in the heap. 00147 * @param hp heap where we are working. 00148 * @param number where to store the result 00149 * @return zero on success, non-zero otherwise. 00150 * */ 00151 #define EGeHeapGetMinVal(hp,number) ({\ 00152 EGeHeap_t*const __EGehp = (hp);\ 00153 __EGehp->sz ? (EGlpNumCopy(number,__EGehp->cn[0]->val),0):1;}) 00154 00155 /* ========================================================================= */ 00156 /** @brief get the minimum conector in the heap, if the heap is empty, return 00157 * NULL. 00158 * @param hp eap where we are working. 00159 * @return pointer to the minimum element in the heap. 00160 * */ 00161 #define EGeHeapGetMin(hp) ({\ 00162 EGeHeap_t*const __EGehp = (hp);\ 00163 __EGehp->sz ? __EGehp->cn[0] : 0;}) 00164 00165 /* ========================================================================= */ 00166 /** @brief resize the heap cn array to the given size, if the new size is zero, 00167 * it is equivalent to free the internal memory, and left the heap as an empty 00168 * heap with zero space. 00169 * @param hp heap where we are working. 00170 * @param new_sz hew size for the cn array . 00171 * */ 00172 #define EGeHeapResize(hp,new_sz) ({\ 00173 EGeHeap_t*const __EGehp = (hp);\ 00174 const unsigned int __EGehp_nsz = (new_sz);\ 00175 __EGehp->cn = EGrealloc((__EGehp->cn), __EGehp_nsz * sizeof(EGeHeapCn_t*));\ 00176 __EGehp->max_sz = __EGehp_nsz;}) 00177 00178 /* ========================================================================= */ 00179 /** @brief return the index of the father of the given index. 00180 * @param d breadth of the heap. 00181 * @param id position in the array to wich we want to compute it's father. 00182 * */ 00183 #define EGeHeapFatherId(d,id) ((id)?(((id)-1)/(d)):0) 00184 00185 /* ========================================================================= */ 00186 /** @brief move an element in the heap up in the heap (position 0 is the top, 00187 * this kind of move is neded whenever we decrease the value in a heap element). 00188 * @param hp heap where we are working. 00189 * @param hcn element in the heap to move. 00190 * @return zero on success, non-zero otherwise. 00191 * */ 00192 #define EGeHeapSiftUp(hp,hcn) ({\ 00193 EGeHeap_t*const __EGehp = (hp);\ 00194 EGeHeapCn_t*const __EGecn = (hcn);\ 00195 unsigned int __EGcpos = __EGecn->pos;\ 00196 unsigned int __EGfpos = EGeHeapFatherId(__EGehp->d,__EGcpos);\ 00197 EGeHeapCn_t*__EGfcn = __EGehp->cn[__EGfpos];\ 00198 WARNINGL(EG_EHEAP_DEBUG,__EGehp->sz<=__EGcpos,"Heap Conector out of range");\ 00199 while(__EGcpos && \ 00200 EGlpNumIsLess(__EGecn->val,__EGfcn->val))\ 00201 {\ 00202 __EGfcn->pos = __EGcpos;\ 00203 __EGehp->cn[__EGcpos] = __EGfcn;\ 00204 __EGcpos = __EGfpos;\ 00205 __EGfpos = EGeHeapFatherId(__EGehp->d,__EGcpos);\ 00206 __EGfcn = __EGehp->cn[__EGfpos];\ 00207 }\ 00208 __EGecn->pos = __EGcpos;\ 00209 __EGehp->cn[__EGcpos] = __EGecn;\ 00210 0;}) 00211 00212 /* ========================================================================= */ 00213 /** @brief Add an element to the heap 00214 * @param hp heap where to add the element. 00215 * @param hcn element to be added. 00216 * @return zero on success, non-zero otherwise. 00217 * */ 00218 #define EGeHeapAdd(hp,hcn) ({\ 00219 EGeHeap_t*const __EGlhp = (hp);\ 00220 EGeHeapCn_t*const __EGlcn = (hcn);\ 00221 __EGlhp->sz == __EGlhp->max_sz ? (fprintf(stderr,"Heap "#hp" is full, can't"\ 00222 " add element "#hcn), 1) : (__EGlcn->pos = __EGlhp->sz, \ 00223 __EGlhp->cn[__EGlhp->sz] = __EGlcn, __EGlhp->sz +=1, EGeHeapSiftUp(__EGlhp,__EGlcn), 0);}) 00224 00225 /* ========================================================================= */ 00226 /** @brief Give the first child for a given position. 00227 * @param id position that we want to get the first child. 00228 * @param d breath of the heap. */ 00229 #define EGeHeapFirstChildId(d,id) ((d)*(id)+1) 00230 00231 /* ========================================================================= */ 00232 /** @brief Move an element down in the heap (position 0 is the 00233 * top), this kind of operation is needed whenever we increase the value in a 00234 * heap element. 00235 * @param hp heap where we are working. 00236 * @param hcn element in the heap to move. 00237 * @return zero on success, non-zero otherwise. 00238 * */ 00239 #define EGeHeapSiftDown(hp,hcn) ({\ 00240 EGeHeap_t*const __EGehp = (hp);\ 00241 EGeHeapCn_t*const __EGecn = (hcn);\ 00242 const unsigned int __EGhsz = __EGehp->sz;\ 00243 unsigned int __EGcpos = __EGecn->pos;\ 00244 unsigned int __EGfchd = EGeHeapFirstChildId(__EGehp->d,__EGcpos);\ 00245 unsigned int __EGlchd = __EGfchd + __EGehp->d;\ 00246 EGeHeapCn_t*__EGcchd = 0;\ 00247 register unsigned int __EGehi = 0;\ 00248 EXITL(EG_EHEAP_DEBUG, __EGcpos > __EGhsz , "Element "#hcn" out of range"\ 00249 " in the heap "#hp);\ 00250 while(__EGfchd < __EGhsz)\ 00251 {\ 00252 /* detect the minimum child */\ 00253 __EGcchd = __EGehp->cn[__EGfchd];\ 00254 for(__EGehi = __EGlchd > __EGhsz ? __EGhsz-1 : __EGlchd-1 ;\ 00255 __EGehi > __EGfchd ; __EGehi--)\ 00256 if(EGlpNumIsLess(__EGehp->cn[__EGehi]->val,__EGcchd->val))\ 00257 __EGcchd = __EGehp->cn[__EGehi];\ 00258 /* if the minimum child is less than the current position, move the minimum\ 00259 * child to the position of the current element */\ 00260 if(EGlpNumIsLess(__EGcchd->val,__EGecn->val))\ 00261 {\ 00262 __EGfchd = __EGcchd->pos;\ 00263 __EGcchd->pos = __EGcpos;\ 00264 __EGehp->cn[__EGcpos] = __EGcchd;\ 00265 __EGecn->pos = __EGcpos = __EGfchd;\ 00266 __EGehp->cn[__EGcpos] = __EGecn;\ 00267 __EGfchd = EGeHeapFirstChildId(__EGehp->d,__EGcpos);\ 00268 __EGlchd = __EGfchd + __EGehp->d;\ 00269 }\ 00270 /* else we exit the main loop */\ 00271 else __EGfchd = UINT_MAX;\ 00272 }\ 00273 0;}) 00274 00275 /* ========================================================================= */ 00276 /** @brief Change the value of an element in the heap. 00277 * @param hp heap where we are working. 00278 * @param hcn element in the heap that we are going to change it's value. 00279 * @param new_val new value for the element. 00280 * @return zero on success, non-zero otherwise. 00281 * */ 00282 #define EGeHeapChangeVal(hp,hcn,new_val) ({\ 00283 (EGlpNumIsLess(new_val,(hcn)->val)) ? (EGlpNumCopy((hcn)->val,new_val),EGeHeapSiftUp(hp,hcn)) : (EGlpNumCopy((hcn)->val,new_val),EGeHeapSiftDown(hp,hcn));}) 00284 00285 /* ========================================================================= */ 00286 /** @brief Eliminate an element from the heap, note that the position stored in 00287 * the eliminated element is reset to zero. 00288 * @param hp heap where we are working. 00289 * @param hcn element to eliminate from the heap. 00290 * @return zero on success, non-zero otherwise. 00291 * */ 00292 #define EGeHeapDel(hp,hcn) ({\ 00293 EGeHeap_t*const __EGlhp = (hp);\ 00294 unsigned int const __EGlcn = (hcn)->pos;\ 00295 (hcn)->pos = EG_EHEAP_POISON;\ 00296 (__EGlhp->sz) -= 1;\ 00297 __EGlhp->cn[__EGlcn] = __EGlhp->cn[__EGlhp->sz];\ 00298 __EGlhp->cn[__EGlcn]->pos = __EGlcn;\ 00299 __EGlhp->cn[__EGlhp->sz] = 0;\ 00300 __EGlhp->sz ? EGeHeapSiftDown(__EGlhp,__EGlhp->cn[__EGlcn]):0;}) 00301 00302 /* ========================================================================= */ 00303 /** @brief Check the integrity of the given heap. 00304 * @param hp heap to check. 00305 * @return zero on success, non-zero otherwise. 00306 * */ 00307 #if EG_EHEAP_DEBUG <= DEBUG 00308 #define EGeHeapCheck(hp) ({\ 00309 EGeHeap_t*const __EGehp = (hp);\ 00310 register unsigned int __EGehi = __EGehp->sz;\ 00311 if(__EGehi)\ 00312 while(--__EGehi)\ 00313 if(__EGehp->cn[__EGehi]->pos != __EGehi || EGlpNumIsLess( __EGehp->cn[\ 00314 __EGehi]->val,__EGehp->cn[EGeHeapFatherId(__EGehp->d,__EGehi)]->val))\ 00315 {\ 00316 MESSAGE(EG_EHEAP_DEBUG,"Element %u is wrong, pos %u val [%lf,%lf]"\ 00317 ,__EGehi, __EGehp->cn[__EGehi]->pos, \ 00318 EGlpNumToLf(__EGehp->cn[__EGehi]->val), \ 00319 EGlpNumToLf(__EGehp->cn[EGeHeapFatherId(__EGehp->d,__EGehi)]->val));\ 00320 break;\ 00321 }\ 00322 __EGehi;}) 00323 #else 00324 #define EGeHeapCheck(hp) 0 00325 #endif 00326 00327 /* ========================================================================= */ 00328 /** @brief set the breath of the heap, this function must be called only when 00329 * the heap is empty. 00330 * @param hp heap to set breath. 00331 * @param width new with for the heap. 00332 * @return zero on success, non-zero otherwise. 00333 * */ 00334 #define EGeHeapChangeD(hp,width) ({\ 00335 EGeHeap_t*const __EGehp = (hp);\ 00336 __EGehp->sz ? 1 : (__EGehp->d = (width), 0);}) 00337 00338 /* ========================================================================= */ 00339 /** @} */ 00340 /* end of eg_eheap.h */ 00341 #endif
1.4.5