lib/quickHeap.c

Go to the documentation of this file.
00001 /* quickHeap - Heap implemented as an array for speed.
00002  *
00003  * This file is copyright 2002 Jim Kent, but license is hereby
00004  * granted for all use - public, private or commercial.
00005  *
00006  *    The array can be resized as it grows.
00007  *  By preserving the relationship that the children of n are at 2n+1 and 2n+2,
00008  *  and therefore the parent of n is at (n-1)/2, we can save alot of pointer
00009  *  manipulation and get some speed.  
00010  *    This routine could for instance be used at the heart of a multi-way mergesort
00011  *  or other situation such as a priority queue.
00012  *
00013  * Maintaining the heap is quick and easy since
00014  * we just use an array with the following relationships:
00015  * children(n) == 2n+1,2n+2. parent(n) == (n-1)/2.
00016  * The highest score is always at the top of the heap in 
00017  * position 0. When the top element is consumed and 
00018  * and the next element for the previously top elem is 
00019  * set in, we simply balance the heap to maintain the heap property
00020  * by swapping with the largest child until both children 
00021  * are smaller, or we hit the end of the array (==heapCount).
00022  * Also note that scores are not necessarily unique, heap members
00023  * may have equal score.  So A parent need not only be greater
00024  * than its children, it may also be equal to them.
00025  */
00026 
00027 #include "common.h"
00028 #include "quickHeap.h"
00029 
00030 static char const rcsid[] = "$Id: quickHeap.c,v 1.1 2005/10/21 05:36:08 galt Exp $";
00031 
00032 
00033 struct quickHeap *newQuickHeap(int initSize, 
00034    int (*compare )(const void *elem1,  const void *elem2))
00035 /* Create a new array quick heap of initial size specified,
00036  * The compare function must return > 0 if elem1 > elem2, etc.*/
00037 {
00038 struct quickHeap *h;
00039 if (initSize < 1)
00040     errAbort("invalid initial size for newQuickHeap: %d",initSize);
00041 AllocVar(h);
00042 h->heapCount=0;
00043 h->heapMax = initSize;
00044 h->heap = AllocN(void *,h->heapMax);
00045 h->compareFunc = compare;
00046 return h;
00047 }
00048 
00049 
00050 void freeQuickHeap(struct quickHeap **pH)
00051 /* Heap needs more space, double the size of the array preserving elements */
00052 {
00053 struct quickHeap *h = *pH;
00054 freez(&h->heap);
00055 freez(pH);
00056 }
00057 
00058 static void expandQuickHeap(struct quickHeap *h)
00059 /* Heap needs more space, double the size of the array preserving elements */
00060 {
00061 int newSize = h->heapMax * 2;
00062 ExpandArray(h->heap, h->heapMax, newSize);
00063 h->heapMax = newSize;
00064 }
00065 
00066 void addToQuickHeap(struct quickHeap *h, void *elem)
00067 /* add to heap at end (expands array if needed), rebalance */
00068 {
00069 int n, p;   /* node, parent */
00070 if (h->heapCount >= h->heapMax)
00071     expandQuickHeap(h);
00072 /* preserve heap property as it grows */
00073 n = h->heapCount;
00074 h->heap[h->heapCount++] = elem;
00075 p = (n-1)/2;
00076 while (n > 0 && h->compareFunc(h->heap[p], h->heap[n]) < 0)
00077     {
00078     void *temp = h->heap[p];
00079     h->heap[p] = h->heap[n];
00080     h->heap[n] = temp;
00081     n = p;
00082     p = (n-1)/2;
00083     }
00084 }
00085 
00086 
00087 static void quickHeapBalanceWithChildren(struct quickHeap *h, int n)
00088 /* only the value of the n-th element has changed, now rebalance */
00089 {
00090 int c1, c2, hc;   /* child1, child2, heapCount */
00091 if (n < 0 || n >= h->heapCount)
00092     errAbort("attempt to quickHeapBalanceWithChildren with invalid value "
00093                 "for n: %d, heapCount=%d", n, h->heapCount);
00094 /* balance heap - swap node with biggest child until both children are 
00095  * either less or equal or hit end of heap (no more children) */
00096 hc = h->heapCount;
00097 c1 = 2*n+1;
00098 c2 = 2*n+2;
00099 while (TRUE)
00100     {
00101     void *temp = NULL;
00102     int bestc = n;
00103     if (c1 < hc && h->compareFunc(h->heap[c1], h->heap[bestc]) > 0)
00104         bestc = c1;
00105     if (c2 < hc && h->compareFunc(h->heap[c2], h->heap[bestc]) > 0)
00106         bestc = c2;
00107     if (bestc == n)
00108         break;
00109     temp = h->heap[bestc];
00110     h->heap[bestc] = h->heap[n];
00111     h->heap[n] = temp;
00112     n = bestc;
00113     c1 = 2*n+1;
00114     c2 = 2*n+2;
00115     }
00116 }
00117 
00118 
00119 void quickHeapTopChanged(struct quickHeap *h)
00120 /* only the value of the top element has changed, now rebalance */
00121 {
00122 /* balance heap - swap node with biggest child until both children are 
00123  * either less or equal or hit end of heap (no more children) */
00124 quickHeapBalanceWithChildren(h,0);
00125 }
00126 
00127 boolean quickHeapEmpty(struct quickHeap *h)
00128 /* return TRUE if quick heap is empty, otherwise FALSE */
00129 {
00130 return h->heapCount < 1;
00131 }
00132 
00133 static void removeFromQuickHeapN(struct quickHeap *h, int n)
00134 /* Remove element n from the heap by swapping 
00135  * it with the last element in the heap and rebalancing.
00136  * If heap is empty it will errAbort, but that should not happen. */
00137 {
00138 if (n < 0 || n >= h->heapCount)
00139     errAbort("attempt to removeFromQuickHeapN with invalid value "
00140                 "for n: %d, heapCount=%d", n, h->heapCount);
00141 h->heap[n] = h->heap[--h->heapCount]; /* wipes out n by moving tail to it */
00142 h->heap[h->heapCount] = NULL; /* not needed but clean */
00143 /* balance heap - swap node with biggest child until both children are 
00144  * either less or equal or hit end of heap (no more children) */
00145 if (n < h->heapCount)  /* i.e. true for all but when n was the tail */
00146     quickHeapBalanceWithChildren(h,n);
00147 }
00148 
00149 
00150 static int findElemInQuickHeap(struct quickHeap *h, void *elem)
00151 /* Do a linear search in heap array for elem,
00152  * return position n or -1 if not found */
00153 {
00154 int n = -1;
00155 while (++n < h->heapCount)
00156     {
00157     if (h->heap[n] == elem)
00158         return n;
00159     }
00160 return -1;    
00161 }
00162 
00163 
00164 boolean removeFromQuickHeapByElem(struct quickHeap *h, void *elem)
00165 /* Do a linear search in heap array for elem,
00166  * then remove it by position n. Return TRUE
00167  * if found and removed, otherwise return FALSE. */
00168 {
00169 int n = findElemInQuickHeap(h, elem);
00170 if (n < 0) 
00171     return FALSE;
00172 removeFromQuickHeapN(h,n);
00173 return TRUE;
00174 }
00175 
00176 void *peekQuickHeapTop(struct quickHeap *h)
00177 /* return the top element or NULL if empty */
00178 {
00179 if (h->heapCount < 1) 
00180     return NULL;
00181 return h->heap[0];    
00182 }
00183 
00184 void *removeQuickHeapTop(struct quickHeap *h)
00185 /* Return elem (pointer) in heap array[0]
00186  * which will be NULL if heap is empty.
00187  * Then that top element if found is removed. */
00188 {
00189 void *result = h->heap[0]; 
00190 /* this is ok, but depends on removeFromQuickHeapN NULLing as it empties */   
00191 if (h->heapCount > 0) 
00192     {
00193     removeFromQuickHeapN(h,0);
00194     }
00195 return result;
00196 }
00197 

Generated on Tue Dec 25 18:39:31 2007 for blat by  doxygen 1.5.2