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 */
#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");
}
用例测试结果: