/***************************************************************************** * PriorQue.c - implement priority queue, using regular binary trees * * (that guarantees only average time of NlogN...) and with the following * * operations: * * 1. PQInit(&PQ) - initialize the queue, must be called before usage. * * 2. PQEmpty(PQ) - returns TRUE iff PQ is empty. * * 3. PQCompFunc(&CompFunc) - sets (a pointer to) the function that is * * used to compere two items in the queue. the function should get two * * item pointers, and should return >1, 0, <1 as comparison result for * * greater than, equal, or less than respectively. * * 4. PQFirst(&PQ, Delete) - returns the first element of the priority * * queue, and delete it from queue if delete is TRUE. * * 5. PQInsert(&PQ, NewItem) - insert NewItem into the queue * * (NewItem is a pointer to it), using the comparison function CompFunc. * * 6. PQDelete(&PQ, OldItem) - Delete old item from the queue * * again using the comparison function CompFunc. * * 7. PQFind(PQ, OldItem) - Find old item in queue, again using the * * comparison function CompFunc. * * 8. PQNext(PQ, CmpItem, NULL) - returns the smallest item which is bigger * * than given item CmpItem. PQ is not modified. Return NULL if none. * * 9. PQPrint(PQ, &PrintFunc) - print the queue in order using the given * * printing function PrintFunc. * *10. PQFree(&PQ, FreeItems) - Free the queue. The items are also freed if * * FreeItems is TRUE. * * * * Written by Gershon Elber, Dec 88 * *****************************************************************************/ #include #include #include "priorque.h" /* Definition des fonction MyFree() ( free() ) et MyMalloc() (malloc() */ void * MyMalloc( size_t ); void MyFree(void*); #define SIGN(x) ((x) > 0 ? 1 : ((x) < 0 ? -1 : 0)) #define PQ_NEW_NODE(PQ) { \ PQ = (PriorQue *) MyMalloc(sizeof(PriorQue)); \ (PQ) -> Right = (PQ) -> Left = NULL; \ (PQ) -> Data = NULL; } #define PQ_FREE_NODE(PQ) { MyFree((char *) (PQ)); PQ = NULL; } static PQCompFuncType CompFunc; // = (PQCompFuncType) strcmp; /****************************************************************************** * PQEmpty - initialize the queue... * ******************************************************************************/ void PQInit(PriorQue **PQ) { *PQ = NULL; } /****************************************************************************** * PQEmpty - returns TRUE iff PQ priority queue is empty. * ******************************************************************************/ int PQEmpty(PriorQue *PQ) { return PQ == NULL; } /****************************************************************************** * PQCompFunc - sets (a pointer to) the function that is used to compere two * * items in the queue. The function should get two item pointers, and should * * return >1, 0, <1 as comparison result for greater than, equal, or less than * * respectively. * ******************************************************************************/ void PQCompFunc(PQCompFuncType NewCompFunc) { CompFunc = NewCompFunc; } /****************************************************************************** * PQFirst - returns the first element of the priority queue, and delete it * * from queue if Delete is TRUE. return NULL if empty queue * ******************************************************************************/ void * PQFirst(PriorQue **PQ, int Delete) { void * Data; PriorQue *Ptemp = (*PQ); if (*PQ == NULL) return NULL; while (Ptemp -> Right != NULL) Ptemp = Ptemp -> Right; /* Find smallest item. */ Data = Ptemp -> Data; if (Delete) PQDelete(PQ, Data); return Data; } /****************************************************************************** * PQInsert - insert new item into the queue (NewItem is a pointer to it), * * using given compare function CompFunc. CompFunc should return >1, 0, <1 * * as two item comparison result for greater than, equal, or less than * * respectively. * * Insert is always as a leaf of the tree. * * Return pointer to old data if was replaced or NULL if the item is new. * ******************************************************************************/ void * PQInsert(PriorQue **PQ, void * NewItem) { int Compare; void * Data; if ((*PQ) == NULL) { PQ_NEW_NODE(*PQ); (*PQ) -> Data = NewItem; return NULL; } else { Compare = (*CompFunc)(NewItem, (*PQ) -> Data); Compare = SIGN(Compare); switch (Compare) { case -1: return PQInsert(&((*PQ) -> Right), NewItem); case 0: Data = (*PQ) -> Data; (*PQ) -> Data = NewItem; return Data; case 1: return PQInsert(&((*PQ) -> Left), NewItem); } } return NULL; /* Makes warning silent. */ } /****************************************************************************** * PQDelete - Delete old item from the queue, again using the comparison * * function CompFunc. * * Returns pointer to Deleted item if was fould and deleted, NULL otherwise. * ******************************************************************************/ void * PQDelete(PriorQue **PQ, void * OldItem) { int Compare; PriorQue *Ptemp; void * Data; void * OldData; if ((*PQ) == NULL) return NULL; else { Compare = (*CompFunc)(OldItem, (*PQ) -> Data); Compare = SIGN(Compare); switch (Compare) { case -1: return PQDelete(&((*PQ) -> Right), OldItem); case 0: OldData = (*PQ) -> Data; /* The returned deleted item. */ if ((*PQ) -> Right == NULL && (*PQ) -> Left == NULL) { /* Thats easy - we delete a leaf: */ Data = (*PQ) -> Data; PQ_FREE_NODE(*PQ); /* Note *PQ is also set to NULL here. */ } else if ((*PQ) -> Right != NULL) { /* replace this node by the biggest in the Right branch: */ /* move once to the Right and then Left all the time... */ Ptemp = (*PQ) -> Right; if (Ptemp -> Left != NULL) { while (Ptemp -> Left -> Left != NULL) Ptemp = Ptemp -> Left; Data = Ptemp -> Left -> Data;/*Save the data pointer.*/ PQDelete(&(Ptemp -> Left), Data); /* Delete recurs. */ (*PQ) -> Data = Data; /* And put that data instead...*/ } else { Data = Ptemp -> Data; /* Save the data pointer. */ PQDelete(&((*PQ) -> Right), Data); /* Delete recurs. */ (*PQ) -> Data = Data; /* And put that data instead...*/ } } else /* Left != NULL. */ { /* replace this node by the biggest in the Left branch: */ /* move once to the Left and then Right all the time... */ Ptemp = (*PQ) -> Left; if (Ptemp -> Right != NULL) { while (Ptemp -> Right -> Right != NULL) Ptemp = Ptemp -> Right; Data = Ptemp -> Right -> Data; /* Save data pointer. */ PQDelete(&(Ptemp -> Right), Data); /*Delete recurs. */ (*PQ) -> Data = Data; /* And put that data instead...*/ } else { Data = Ptemp -> Data; /* Save the data pointer. */ PQDelete(&((*PQ) -> Left), Data); /* Delete recurs. */ (*PQ) -> Data = Data; /* And put that data instead...*/ } } return OldData; case 1: return PQDelete(&((*PQ) -> Left), OldItem); } } return NULL; /* Makes warning silent. */ } /****************************************************************************** * PQFind - Find old item from the queue, again using the comparison * * function CompFunc. * * Returns pointer to item if was fould, NULL otherwise. * ******************************************************************************/ void * PQFind(PriorQue *PQ, void * OldItem) { int Compare; if (PQ == NULL) { return NULL; } else { Compare = (*CompFunc)(OldItem, PQ -> Data); Compare = SIGN(Compare); switch (Compare) { case -1: return PQFind(PQ -> Right, OldItem); case 0: return PQ -> Data; case 1: return PQFind(PQ -> Left, OldItem); } } return NULL; /* Makes warning silent. */ } /****************************************************************************** * PQNext - returns the smallest item which is bigger than given item CmpItem. * * PQ is not modified. Return NULL if none was found. * * BiggerThan will allways hold the smallest Item bigger than current one. * ******************************************************************************/ void * PQNext(PriorQue *PQ, void * CmpItem, void * BiggerThan) { int Compare; PriorQue *Ptemp; if (PQ == NULL) return BiggerThan; else { Compare = (*CompFunc)(CmpItem, PQ -> Data); Compare = SIGN(Compare); switch (Compare) { case -1: return PQNext(PQ -> Right, CmpItem, PQ -> Data); case 0: /* Found it - if its right tree is not empty, returns its */ /* smallest, else returns BiggerThan... */ if (PQ -> Left != NULL) { Ptemp = PQ -> Left; while (Ptemp -> Right != NULL) Ptemp = Ptemp -> Right; return Ptemp -> Data; } else return BiggerThan; case 1: return PQNext(PQ -> Left, CmpItem, BiggerThan); } } return NULL; /* Makes warning silent. */ } /****************************************************************************** * PQPrint - print the queue in order using the given printing functionq * * PrintFunc. * ******************************************************************************/ void PQPrint(PriorQue *PQ, void (*PrintFunc)(void *)) { if (PQ == NULL) return; PQPrint(PQ -> Right, PrintFunc); (*PrintFunc)(PQ -> Data); PQPrint(PQ -> Left, PrintFunc); } /****************************************************************************** * PQFree - Free the queue. The items are also freed if FreeItems is TRUE. * ******************************************************************************/ void PQFree(PriorQue *PQ, int FreeItem) { if (PQ == NULL) return; PQFree(PQ -> Right, FreeItem); PQFree(PQ -> Left, FreeItem); if (FreeItem) MyFree((char *) PQ -> Data); MyFree((char *) PQ); } /****************************************************************************** * PQFreeFunc - Free queue. Items are also freed by calling FreeFunc on them. * ******************************************************************************/ void PQFreeFunc(PriorQue *PQ, void (*FreeFunc)(void *)) { if (PQ == NULL) return; PQFreeFunc(PQ -> Right, FreeFunc); PQFreeFunc(PQ -> Left, FreeFunc); (FreeFunc)(PQ -> Data); MyFree((char *) PQ); }