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

如何使用C语言写: Generic Queue

2013-02-27 09:56 387 查看
Model
------------------------------------------------------------------------------------------------------------------------



队列也是限制插入和删除位置的表.
主要操作是enqueue和dequeue操作.
enqueue:入队操作.在表的队尾(rear)插入一个元素.
dequeue:出队操作.删除表的队首(front)元素.

本文使用循环数组实现GenericQueue.需要指定capacity.缺点是超出容量,无法动态增长.当然,可以仿照list的方式克服这个问题.
完整代码详见我的github(https://github.com/gnudennis/ds_c)(genric-queue.h
generic-queue.c generic-queue-test.c)


核心代码
------------------------------------------------------------------------------------------------------------------------
0. Generic Queue定义

typedef void *ElementAddr;
typedef void (*PfCbFree)(ElementAddr);

typedef struct QueueRecord
{
ElementAddr	*array;
int		capacity;
int		elemsize;
int		front;
int		rear;
int		size;
PfCbFree	freefn;
} *Queue;


1. API

/* Create a new queue */
Queue queue_create(int elemsize, int capacity, PfCbFree freefn);

/* Dispose the queue */
void queue_dispose(Queue que);

/* Make the give queue empty */
void queue_make_empty(Queue que);

/* Return true if the queue is empty */
int queue_is_empty(Queue que);

/* Return true if the queue is full */
int queue_is_full(Queue que);

/* Insert a new element onto queue */
void queue_enqueue(Queue que, ElementAddr elemaddr);

/* Delete the front element off the queue */
void queue_dequeue(Queue que);

/* Fetch the front element from the queue */
void queue_front(Queue que, ElementAddr elemaddr);

/* Fetch and Delete the front element from the queue */
void queue_front_and_dequeue(Queue que, ElementAddr elemaddr);


2.Implementation

/* Create a new queue with capacity */
Queue
queue_create(int elemsize, int capacity, PfCbFree freefn)
{
Queue que;

que = malloc(sizeof(struct QueueRecord));
if ( que == NULL ) {
fprintf(stderr, "Out of memory\n");
exit(1);
}

que->elemsize = elemsize;
que->capacity = capacity > MIN_QUEUE_SIZE ? capacity : MIN_QUEUE_SIZE;

que->array = malloc(elemsize * que->capacity);
if ( que->array == NULL ) {
fprintf(stderr, "Out of memory\n");
exit(1);
}
que->front = 1;
que->rear = 0;
que->size = 0;
que->freefn = freefn;

return que;
}

/* Dispose the queue */
void
queue_dispose(Queue que)
{
if (que != NULL) {
queue_make_empty(que);
free(que->array);
free(que);
}
}

/* Make the give queue empty */
void
queue_make_empty(Queue que)
{
if ( que->freefn ) {
int i;
for ( i = 0; i < que->size; ++i) {
free((char *)que->array +
que->elemsize * i);
}
}
que->size = 0;
que->front = 1;
que->rear = 0;
}

/* Return true if the queue is empty */
int
queue_is_empty(Queue que)
{
return que->size == 0;
}

/* Return true if the queue is full */
int
queue_is_full(Queue que)
{
return que->size == que->capacity;
}

static int
successor(Queue que, int index)
{
if ( ++index == que->capacity)
index = 0;
return index;
}

/* Insert a new element onto queue(rear) */
void
queue_enqueue(Queue que, ElementAddr elemaddr)
{
void *target;

if ( queue_is_full(que) ) {
fprintf(stderr, "Full queue\n");
exit(1);
}
que->rear = successor(que, que->rear);
target = (char *)que->array + que->elemsize * que->rear;
memcpy(target, elemaddr, que->elemsize);
que->size++;
}

/* Delete the front element off the queue */
void
queue_dequeue(Queue que)
{
if ( queue_is_empty(que) ) {
fprintf(stderr, "Empty queue\n");
exit(1);
}
if ( que->freefn ) {
void *target = (char *)que->array +
que->front * que->elemsize;
que->freefn(target);
}
que->size--;
que->front = successor(que, que->front);
}

/* Fetch the front element from the queue */
void
queue_front(Queue que, ElementAddr elemaddr)
{
void *target = (char *)que->array +
que->front * que->elemsize;
memcpy(elemaddr, target, que->elemsize);
}

/* Fetch and Delete the front element from the queue */
void
queue_front_and_dequeue(Queue que, ElementAddr elemaddr)
{
void *target;

if ( queue_is_empty(que) ) {
fprintf(stderr, "Empty queue\n");
exit(1);
}

target = (char *)que->array +
que->front * que->elemsize;
memcpy(elemaddr, target, que->elemsize);

que->size--;
que->front = successor(que, que->front);
}


分析
----------------
本文使用循环数组实现GenericQueue.需要指定capacity.既然是循环数组,就是围成一个圈.也就插入第一个元素没有必要非要放在0处啦.
初始状态:
{

que->size = 0;

que->front = 1;

que->rear = 0;
}
说明这样第一次enqueue操作放在array[1]处,当然:这不是必须的,取决于你想放在那里.
#define mxx
{

que->size = 0;
que->front =m+1;

que->rear = m;
}
就放在array[m+1]处.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: