数据结构队列之环形队列的动态数组实现:queue

queue: 也是一种线性的数据结构,其操作一般来讲也是受限的,典型特征是(First in, First out, FIFO)先进先出;

        进入队列的元素总是在队列的tail入队,离开队列的元素总是从队列的head离开。

其实实现有多种方式:

1. 用链表实现,head指针指向queue的head, tail指针指向queue的tail;

                     使用的内存空间就是队列中所有元素节点的空间,但是此实现无法随机访问队列中的元素(这是链表本质决定的)。

                     使用链表的实现会当元素频繁入队的话,会频繁的分配内存空间; 当元素入队时也要频繁地释放元素的内存空间。

2. 用数组实现:

         a. 静态数组的实现:有限容量的队列,一般情况下通过实现环形queue以实现数组空间的充分利用。此实现,使用于具体需求确定的情形。 

         b. 动态数组的实现:动态数组实现的环形queue,除了具有静态数组实现的环形queue的优点外,还能根据需求的变化,自动的调整队列的内存。(可谓有点智能)。 


环形队列的实现要点:可谓是队列为空的标记,

为了简便起见,本文的实现通过将tail永远指向queue的最后一个元素的下一个元素空间位置,即所谓的留出最后一个的元素空间作为标记;

1. 初始化 queue.head == queue.tail 为空; (tail始终指向队列中最后一个元素的下一个位置);

2. enqueue: 元素入队,(因为tail指向的一个节点的元素空间总是预留的), 是否需要环形调整,queue是否已满(++tail == head),队满增加存储空间,调整队列;

3. dequeue:  队列不为空,将对头元素出对,是否需要环形调整,预留空间是否过多,如果是做相应的调整。

4.队列的销毁;

注意,队列空,队列满的标志。


用动态数组实现的环形队列的代码如下:


1. queue的接口规范文件:queue.h

#ifndef QUEUE_H
#define QUEUE_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* initial queue capacity in terms of elements */
#define	QUEUE_INITIAL_SIZE	1 //1024; 1 just used to test in case;

#define CHECK_MEM(p) \
if ((p) == NULL) { \
    fprintf(stderr, "out of memory: in file %s, line %d, function %s.\n", __FILE__, __LINE__, __FUCTION__); \
    exit(1); \
}


typedef struct queue_t {
    void    *base;
    void    *head;              /* head points to oldest element */
    void    *tail;              /* tail points to the next element position to the earliest element */
    int	    element_size;	    /* element size */
    int	    capacity;	        /* capacity */
} queue;


/* queue operations */
void queue_init(queue *queue, int element_size);
void queue_free(queue *queue);

int    queue_empty(queue *queue);
void   enqueue(queue *queue, void *element);
void * dequeue(queue *queue);
int    queue_size(queue *queue);
void   queue_clear(queue *queue);


#endif  /* QUEUE_H */


2. queue功能实现代码:queue.c

#include "queue.h"


/* queue operations */
void queue_init(queue *queue, int element_size) {
    queue->base = (void *) malloc(QUEUE_INITIAL_SIZE * element_size);
    if (queue->base == NULL) {
        fprintf(stderr, "out of memory (in file %s : line %d : fuction %s.)\n", __FILE__, __LINE__, __FUNCTION__);
        exit(1);
    }

    queue->head = queue->base;
    queue->tail = queue->base;
    queue->element_size = element_size;
    queue->capacity = QUEUE_INITIAL_SIZE * element_size;
}

void queue_free(queue *queue) {
    if (queue->base != NULL) {
        free(queue->base);
        queue->base = NULL;
    }

    queue->head = NULL;
    queue->tail = NULL;
    queue->element_size = 0;
    queue->capacity = 0;
}

int queue_empty(queue *queue) {
    return (queue->head == queue->tail) ? 1 : 0;
}

void enqueue(queue *queue, void *element) {
    void *newbase;
    int n;

    memcpy(queue->tail, element, queue->element_size);
    queue->tail += queue->element_size;
    if (queue->tail == (queue->base + queue->capacity)) {
        queue->tail = queue->base;
    }

    /* queue not full, done */
    if (queue->tail != queue->head) return;

    /* queue is full, allocate more memory and move data */
    newbase = (void *) malloc(queue->capacity << 1);

    if (newbase == NULL) {
        fprintf(stderr, "out of memory (in file %s : line %d : fuction %s.)\n", __FILE__, __LINE__, __FUNCTION__);
        queue_free(queue);
        exit(1);
    }

    n = queue->base + queue->capacity - queue->head;
    memcpy(newbase, queue->head, n);

    if(queue->tail > queue->base) {
        memcpy(newbase + n, queue->base, queue->tail - queue->base);
    }

    free(queue->base);
    queue->base = newbase;
    queue->head = queue->base;
    queue->tail = queue->base + queue->capacity;
    queue->capacity <<= 1;
}


void * dequeue(queue *queue) {
    void *p;
    void *newbase;
    if(queue_empty(queue))	return NULL;

    int byte_size = queue_size(queue) * queue->element_size;
    int n;
    if(byte_size > QUEUE_INITIAL_SIZE && byte_size < (queue->capacity >> 1) ) {
        if(queue->head <= queue->tail) {
            n = queue->tail - queue->head;
            newbase = (void *) malloc(n);
            if (newbase == NULL) {
                fprintf(stderr, "memory error: (in file %s : line %d : fuction %s.)\n", __FILE__, __LINE__, __FUNCTION__);
                queue_free(queue);
                exit(1);
            }
            memcpy(newbase, queue->head, n);
        } else {
            n = queue->tail + queue->capacity - queue->head;
            newbase = (void *) malloc(queue->capacity >> 1);
            if (newbase == NULL) {
                fprintf(stderr, "memory error: (in file %s : line %d : fuction %s.)\n", __FILE__, __LINE__, __FUNCTION__);
                queue_free(queue);
                exit(1);
            }

            int right = queue->base + queue->capacity - queue->head;
            memcpy(newbase, queue->head, right);
            memcpy(newbase + right, queue->base, queue->tail - queue->base);
        }
        free(queue->base);
        queue->base = newbase;
        queue->head = newbase;
        queue->tail = newbase + n;
        queue->capacity >>= 1;
    }

    p = queue->head;
    queue->head += queue->element_size;
    if(queue->head == (queue->base + queue->capacity)) {
        queue->head = queue->base;
    }

    return p;
}


int queue_size(queue *queue) {
    if(queue->head <= queue->tail) {
        return  (queue->tail - queue->head) / queue->element_size;
    }else {
        return (queue->tail + queue->capacity - queue->head) / queue->element_size;
    }
}


/* just clear elements to queue empty, but don't free memory */
void queue_clear(queue *queue) {
    queue->head = queue->base;
    queue->tail = queue->base;
}


3. 对queue的测试代码:main.c

#include "queue.h"


void printArray(int a[], int len);

int main(int argc, char* argv[]) {

    int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int len = sizeof(a)/sizeof(a[0]);
    int i;
    queue queue;

    printArray(a, len);
    queue_init(&queue, sizeof(a[0]));

//    printf("queue capacity:%d\n", queue.capacity);
//    printf("queue size: %d\n", queue_size(&queue));

    for(i = 0; i < len; ++i) {
        enqueue(&queue, &a[i]);
//         printf("queue capacity:%d\n", queue.capacity);
//         printf("queue size: %d\n", queue_size(&queue));
    }

//    printf("queue capacity:%d\n", queue.capacity);
//    printf("queue size: %d\n", queue_size(&queue));


    while(!queue_empty(&queue)) {
        printf("%d\t", *(int*)dequeue(&queue));
//        printf("queue capacity:%d\n", queue.capacity);
//        printf("queue size: %d\n", queue_size(&queue));

    }
    printf("\n");

//    printf("queue capacity:%d\n", queue.capacity);
//    printf("queue size: %d\n", queue_size(&queue));

    queue_free(&queue);


    return 0;
}


void printArray(int a[], int len) {
    int i;

    for(i=0; i<len; i++) {
        printf("%d\t", a[i]);
    }

    printf("\n");
}


用例测试结果:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值