eg_eheap.h

Go to the documentation of this file.
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

Generated on Mon Jan 30 08:48:53 2006 for EGlib by  doxygen 1.4.5