00001 00007 /* 00008 Originally written by Justin-Heyes Jones 00009 Modified by Shlomi Fish, 2000 00010 Modified by Florian Festi, 2007 00011 00012 This file is in the public domain (it's uncopyrighted). 00013 00014 Check out Justin-Heyes Jones' A* page from which this code has 00015 originated: 00016 http://www.geocities.com/jheyesjones/astar.html 00017 */ 00018 00019 #include "common.h" 00020 #include "pqueue.h" 00021 00022 /* given an index to any element in a binary tree stored in a linear array with the root at 1 and 00023 * a "sentinel" value at 0 these macros are useful in making the code clearer */ 00024 00025 /* the parent is always given by index/2 */ 00026 #define PQ_PARENT_INDEX(i) ((i)>>1) 00027 #define PQ_FIRST_ENTRY (1) 00028 00029 /* left and right children are index * 2 and (index * 2) +1 respectively */ 00030 #define PQ_LEFT_CHILD_INDEX(i) ((i)<<1) 00031 #define PQ_RIGHT_CHILD_INDEX(i) (((i)<<1)+1) 00032 #define PGetRating(elem) ((elem).rating) 00033 00034 00038 void PQueueInitialise (priorityQueue_t *pq, uint32_t maxElements) 00039 { 00040 pq->maxSize = maxElements; 00041 pq->currentSize = 0; 00042 00043 pq->elements = (priorityQueueElement_t*) malloc(sizeof(priorityQueueElement_t) * (maxElements + 1)); 00044 00045 if (pq->elements == NULL) 00046 Sys_Error("PQueueInitialise: Memory alloc failed!"); 00047 } 00048 00049 void PQueuePush (priorityQueue_t *pq, pos4_t item, priorityQueueRating_t r) 00050 { 00051 uint32_t i, j; 00052 uint32_t currentSize = pq->currentSize; 00053 00054 if (currentSize == pq->maxSize) { 00055 int new_size; 00056 new_size = pq->maxSize * 2; 00057 pq->elements = (priorityQueueElement_t *)realloc(pq->elements, sizeof(*pq->elements) * (new_size + 1)); 00058 pq->maxSize = new_size; 00059 } 00060 00061 /* set i to the first unused element and increment CurrentSize */ 00062 i = (++currentSize); 00063 00064 /* while the parent of the space we're putting the new node into is worse than 00065 * our new node, swap the space with the worse node. We keep doing that until we 00066 * get to a worse node or until we get to the top 00067 * note that we also can sort so that the minimum elements bubble up so we need to loops 00068 * with the comparison operator flipped... */ 00069 00070 while (i > PQ_FIRST_ENTRY && pq->elements[PQ_PARENT_INDEX(i)].rating > r) { 00071 pq->elements[i] = pq->elements[PQ_PARENT_INDEX(i)]; 00072 i = PQ_PARENT_INDEX(i); 00073 } 00074 00075 /* then add the element at the space we created. */ 00076 for (j = 0; j < 4; j++) 00077 pq->elements[i].item[j] = item[j]; 00078 00079 pq->elements[i].rating = r; 00080 00081 pq->currentSize = currentSize; 00082 } 00083 00087 void PQueueFree (priorityQueue_t *pq) 00088 { 00089 free(pq->elements); 00090 } 00091 00095 void PQueuePop (priorityQueue_t *pq, pos4_t item) 00096 { 00097 uint32_t i, j; 00098 uint32_t child; 00099 priorityQueueElement_t * elements = pq->elements; 00100 uint32_t currentSize = pq->currentSize; 00101 priorityQueueElement_t pMaxElement; 00102 priorityQueueElement_t pLastElement; 00103 00104 if (PQueueIsEmpty(pq)) 00105 return; 00106 00107 pMaxElement = elements[PQ_FIRST_ENTRY]; 00108 00109 /* get pointer to last element in tree */ 00110 pLastElement = elements[currentSize--]; 00111 00112 for (j = 0; j < 4; j++) 00113 item[j] = pMaxElement.item[j]; 00114 00115 for (i = PQ_FIRST_ENTRY; (child = PQ_LEFT_CHILD_INDEX(i)) <= currentSize; i = child) { 00116 /* set child to the smaller of the two children... */ 00117 00118 if ((child != currentSize) && (elements[child + 1].rating < elements[child].rating)) 00119 child ++; 00120 00121 if (pLastElement.rating > elements[ child ].rating) 00122 elements[i] = elements[child]; 00123 else 00124 break; 00125 } 00126 00127 elements[i] = pLastElement; 00128 pq->currentSize = currentSize; 00129 }