/* heap.c - example of a priority queue as a heap in an array holding a complete binary tree * This software is PUBLIC DOMAIN as of September 2008. No copyright is claimed. * J. Mayo * * Initial: September 1, 2008 * Last Updated: September 4, 2008 */ #include #include #include /* functions a exported when EXPORT is not set to static */ #if 1 #define EXPORT static #else #define EXPORT #endif /****************************************************************************** * utility macros ******************************************************************************/ #define NR(x) (sizeof(x)/sizeof*(x)) #ifdef NDEBUG # define DEBUG(...) /* DEBUG disabled */ #else # define DEBUG(...) fprintf(stderr, __VA_ARGS__) #endif #ifdef NTRACE # define TRACE(...) /* TRACE disabled */ #else # define TRACE(...) fprintf(stderr, __VA_ARGS__) #endif /****************************************************************************** * heapqueue - a binary heap used as a priority queue ******************************************************************************/ #define HEAPQUEUE_LEFT(i) (2*(i)+1) #define HEAPQUEUE_RIGHT(i) (2*(i)+2) #define HEAPQUEUE_PARENT(i) (((i)-1)/2) struct heapqueue_elm { unsigned d; /* key */ /* TODO: put useful data in here */ }; static struct heapqueue_elm heap[512]; /* test heap */ static unsigned heap_len; /* min heap is sorted by lowest value at root * return non-zero if a>b */ static inline int heapqueue_greaterthan(struct heapqueue_elm *a, struct heapqueue_elm *b) { assert(a!=NULL); assert(b!=NULL); return a->d>b->d; } /* i is the "hole" location * elm is the value to compare against * return new position of hole */ static int heapqueue_ll_siftdown(unsigned i, struct heapqueue_elm *elm) { assert(elm!=NULL); assert(i0 && heapqueue_greaterthan(&heap[HEAPQUEUE_PARENT(i)], elm)) { /* Compare the element with parent */ /* swap element with parent and keep going (keep tracking the "hole") */ heap[i]=heap[HEAPQUEUE_PARENT(i)]; i=HEAPQUEUE_PARENT(i); } return i; } /* removes entry at i */ EXPORT int heapqueue_cancel(unsigned i, struct heapqueue_elm *ret) { /* 1. copy the value at i into ret * 2. put last node into empty position * 3. sift-up if moved node smaller than parent, sift-down if larger than either child */ struct heapqueue_elm *last; assert(ret!=NULL); assert(i%u) (left %d:>%u) (right %d:>%u) (last %d)\n", i, ret->d, i>0 ? (int)HEAPQUEUE_PARENT(i) : -1, i>0 ? heap[HEAPQUEUE_PARENT(i)].d : 0, HEAPQUEUE_LEFT(i)0 && heapqueue_greaterthan(&heap[HEAPQUEUE_PARENT(i)], last)) { /* we already did the compare, so we'll perform the first move here */ TRACE("%s():swap hole %d with entry %d\n", __func__, i, HEAPQUEUE_PARENT(i)); heap[i]=heap[HEAPQUEUE_PARENT(i)]; /* move parent down */ i=heapqueue_ll_siftup(HEAPQUEUE_PARENT(i), last); /* sift the "hole" up */ } else if(HEAPQUEUE_RIGHT(i)0 ? (int)HEAPQUEUE_PARENT(i) : -1, HEAPQUEUE_LEFT(i), HEAPQUEUE_RIGHT(i)); } printf("heap valid? %d (%d entries)\n", heapqueue_isvalid(), heap_len); } EXPORT void heapqueue_test(void) { struct heapqueue_elm elm, tmp; unsigned i; const unsigned testdata[] = { 42, 2, 123, 88, 3, 3, 3, 3, 3, 1, 0, }; /* initialize the array */ heap_len=0; #ifndef NDEBUG /* fill remaining with fake data */ for(i=heap_len;i0) { unsigned valid; i=rand()%heap_len; if(heapqueue_cancel(i, &tmp)) { printf("canceled at %d (data=%d)\n", i, tmp.d); } else { printf("canceled at %d failed!\n", i); break; } // heapqueue_dump(); valid=heapqueue_isvalid(); // printf("heap valid? %d (%d entries)\n", valid, heap_len); if(!valid) { printf("BAD HEAP!!!\n"); heapqueue_dump(); break; } } heapqueue_dump(); /* load the queue with test data again */ for(i=0;i