昨日看了算法导论里讲解的堆排序和优先级队列,于是用C语言写了一个优先级队列的简单实现,该实现的最大特点是队列的元素类型是不确定的,可以对任意数据类型进行操作(甚至是自定义的结构体)。这种处理的核心思想是:队列元素的比较操作与赋值操作都由调用者实现并在优先级队列结构体初始化时传给结构体。具体代码如下:
//PriorityQueue.h /* * PriorityQueue.h * The interface of PriorityQueue, support some basic operations of priority * queue such as insert, maximum, extract_max and so on. And the priority * queue element is not specifical, user can pass any type of element to it * if the element's compare and copy function are implemented. * [email protected] */ #ifndef _PRIORITYQUEUE_H #define _PRIORITYQUEUE_H #define PQ_CAP 100 /* the initialize capability of the proioity queue. */ #define PQ_CAP_INC 50 /* the increment of the proioity queue occur when the capability will be overflow. */ /* error numbers */ #define PQ_NOR_ERR -1 #define PQ_MEM_ERR 1 #define PQ_UNDERFLOW_ERR 2 /* compare fuction, if a > b, return 1, else return 0 */ typedef int (*compare_func) (void *a, void *b); /* copy function, copy pq element *b to *a, if success, return 0, else return error number. */ typedef int (*copy_func) (void *a, void *b); typedef struct priqueue_t { unsigned char *pbytes; int length; int capability; int elemsize; /* pq element size */ compare_func compare; /* compare function for pq element */ copy_func copy; /* copy function for pq element */ void *compare_minimum; /* the minimum element for the compare element */ }priqueue; /* initialize function, compare and copy function must be define first and passed to it */ int pq_init(priqueue *pq, compare_func compare, copy_func copy, void *compare_minimum, int elemsize); int pq_insert(priqueue *pq, void *newelement); int pq_maximum(priqueue *pq, void *max); int pq_extract_max(priqueue *pq, void *max); /* increase the key of index i to newkey */ int pq_increase_key(priqueue *pq, int i, void *newkey); int pq_destroy(priqueue *pq); #endif /* _PRIORITYQUEUE_H */
//PriorityQueue.c #include #include "PriorityQueue.h" /* * The follow tow macro were defined to index the element in priority queue. * pbytes is the pointer to data area, which always be pq->pbytes. * i is the index number. * size is the priority queue elemnt size. */ #define INDEX_SIZE(size) ((size)/sizeof(unsigned char)) #define INDEX(pbytes, i, size) ((pbytes)+(i)*INDEX_SIZE(size)) /* The follow three macros are used to traverse in binary heap */ #define left(i) ((i+1<<1)-1) #define right(i) (i+1<<1) #define parent(i) (i-1>>1) int pq_init(priqueue *pq, compare_func compare, copy_func copy, void *compare_minimum, int elemsize) { int ret; pq->length = 0; pq->capability = PQ_CAP; pq->elemsize = elemsize; pq->compare = compare; pq->copy = copy; if ((pq->compare_minimum = (unsigned char *) malloc(pq->elemsize)) == NULL) return PQ_MEM_ERR; if ((ret = (*pq->copy) (pq->compare_minimum, compare_minimum)) != 0) return ret; if ((pq->pbytes = (unsigned char *) malloc(pq->capability * pq->elemsize)) == NULL) return PQ_MEM_ERR; return 0; } int pq_insert(priqueue *pq, void *newelement) { int ret; if (++pq->length == pq->capability) { pq->capability += PQ_CAP_INC; if ((pq->pbytes =(unsigned char *) realloc(pq->pbytes, pq->capability * pq->elemsize)) == NULL) return PQ_MEM_ERR; } if ((ret = (*pq->copy) (INDEX(pq->pbytes, pq->length-1, pq->elemsize), pq->compare_minimum)) != 0) return ret; pq_increase_key(pq, pq->length-1, newelement); return 0; } int pq_maximum(priqueue *pq, void *max) { int ret; if ((ret = (*pq->copy) (max, pq->pbytes)) != 0) return ret; return 0; } int pq_extract_max(priqueue *pq, void *max) { int ret, l, r, i=0, largest = 0; void *tmp = malloc(pq->elemsize); if (pq->length < 1) return PQ_UNDERFLOW_ERR; if ((ret = (*pq->copy)(max, pq->pbytes)) != 0) goto copy_err; if ((ret = (*pq->copy) (pq->pbytes, INDEX(pq->pbytes, pq->length-1, pq->elemsize))) != 0) goto copy_err; pq->length--; //max_heapify(pq, 0) l = left(i); r = right(i); if (l < pq->length && (*pq->compare) (INDEX(pq->pbytes, l, pq->elemsize), INDEX(pq->pbytes, i, pq->elemsize))) largest = l; else largest = i; if (r < pq->length && (*pq->compare) (INDEX(pq->pbytes, r, pq->elemsize), INDEX(pq->pbytes, largest, pq->elemsize))) largest = r; while(largest != i) { if ((ret = (*pq->copy) (tmp, INDEX(pq->pbytes, i, pq->elemsize))) != 0) goto copy_err; if ((ret = (*pq->copy) (INDEX(pq->pbytes, i, pq->elemsize), INDEX(pq->pbytes, largest, pq->elemsize))) != 0) goto copy_err; if ((ret = (*pq->copy) (INDEX(pq->pbytes, largest, pq->elemsize), tmp)) != 0) goto copy_err; i = largest; l = left(i); r = right(i); if (l < pq->length && (*pq->compare) (INDEX(pq->pbytes, l, pq->elemsize), INDEX(pq->pbytes, i, pq->elemsize))) largest = l; else largest = i; if (r < pq->length && (*pq->compare) (INDEX(pq->pbytes, r, pq->elemsize), INDEX(pq->pbytes, largest, pq->elemsize))) largest = r; } free(tmp); return 0; copy_err: free(tmp); return ret; } int pq_increase_key(priqueue *pq, int i, void *newkey) { int ret; void *tmp = malloc(pq->elemsize); if ((*pq->compare) (INDEX(pq->pbytes, i, pq->elemsize), newkey)) return PQ_NOR_ERR; if ((ret = (*pq->copy) (INDEX(pq->pbytes, i, pq->elemsize), newkey)) != 0) goto copy_err; while (i > 0 && (*pq->compare)(INDEX(pq->pbytes, i, pq->elemsize), INDEX(pq->pbytes, parent(i), pq->elemsize))) { if ((ret = (*pq->copy) (tmp, INDEX(pq->pbytes, i, pq->elemsize))) != 0) goto copy_err; if ((ret = (*pq->copy) (INDEX(pq->pbytes, i, pq->elemsize), INDEX(pq->pbytes, parent(i), pq->elemsize))) != 0) goto copy_err; if ((ret = (*pq->copy) (INDEX(pq->pbytes, parent(i), pq->elemsize), tmp)) != 0) goto copy_err; i = parent(i); } free(tmp); return 0; copy_err: free(tmp); return ret; } int pq_destroy(priqueue *pq) { free(pq->pbytes); free(pq->compare_minimum); return 0; }
//testpq.c #include #include #include #include #include "PriorityQueue.h" #define ARR_SIZE 10 int compare(void *a, void *b) { return *(int *)a > *(int *)b; } int copy(void *a, void *b) { *(int *)a = *(int *)b; return 0; } int main(void) { int a[ARR_SIZE]; int i, tmp, minimum = INT_MIN; priqueue pq; pq_init(&pq, &compare, ©, &minimum, sizeof(int)); srand((int) time(0)); for (i = 0; i < ARR_SIZE; i++) a[i] = rand()%1000; printf("Befor sort:/n"); for (i = 0; i < ARR_SIZE; i++) { printf("%d ", a[i]); } printf("/n"); printf("After sort:/n"); for (i = 0; i < ARR_SIZE; i++) pq_insert(&pq, &a[i]); for (i = 0; i < ARR_SIZE; i++) { pq_extract_max(&pq, &tmp); printf("%d ", tmp); } printf("/n"); pq_destroy(&pq); return 0; }