您的位置:首页 > 编程语言 > C语言/C++

C语言实现的优先级队列

2010-12-14 22:04 363 查看
昨日看了算法导论里讲解的堆排序和优先级队列,于是用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.
* wl861213@gmail.com
*/
#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 <stdlib.h>
#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 <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: