环形队列 C语言


队列是链表的变种,主要却别在于存储方式不同,队列是线性存储结构(支持索引访问,但不可随意增删节点),链表是链式存储结构(不支持随机访问,可随意增删节点)。

环形队列,使队列空间可以循环利用,访问速度和普通队列一致

下面时C语言实现代码:

/*
* 无边界的数据流环形队列缓冲区
**/

#include 
#include 
#include 
#include 

#define min(x,y) ((x)<(y)?(x):(y))

typedef struct __queue {
    unsigned char *buff;           // 线性存储缓冲区
    unsigned head;        // 始终指向队列第一个元素位置
    unsigned tail;        // 始终指向最后一个元素位置的下一个位置, 初始队列头尾相等
    unsigned size;
}QUEUE, *PQUEUE;


// 判断长度是否为2的次幂
bool is_power_of_2(unsigned n)
{
    return ((n != 2) && ((n & (n-1)) == 0));
}

// 获取接近value的最大2的次幂
unsigned roundup_pow_of_two(unsigned value)
{
    if(is_power_of_2(value))
    {
        return value;
    }

    short position = 0;
    while(value != 0)
    {
        value >>= 1;
        ++position;
    }

    return (1 << position);
}

// 创建队列
PQUEUE create_queue( unsigned int size)
{
    if(size < 1) return NULL;
    
    size = roundup_pow_of_two(size);
    PQUEUE pqueue = (PQUEUE)malloc(sizeof(QUEUE));

    pqueue->buff = (char*)malloc(sizeof(unsigned char) * size);
    if(NULL == pqueue->buff) return NULL;

    pqueue->size = size;
    pqueue->head = pqueue->tail = 0;
    return pqueue;
}

unsigned queue_free(PQUEUE pqueue)
{
    unsigned len = pqueue->size;
    if(pqueue->head != pqueue->tail) 
    {
       len = (pqueue->size - pqueue->tail + pqueue->head) & (pqueue->size - 1);
    }

    return len > 1 ? (len-1) : 0;
}

bool queue_empty(PQUEUE pqueue)
{
    return (queue_free(pqueue) == pqueue->size);
}

bool queue_full(PQUEUE pqueue)
{
    return (queue_free(pqueue) == 0);
}

void free_queue(PQUEUE pqueue)
{
    if(NULL == pqueue) return;
    if(pqueue->size > 0)
    {
        free(pqueue->buff);
    }
    free(pqueue);
}

// 插入数据
bool input_queue_data(PQUEUE pqueue, void* data, unsigned data_len)
{
    if(NULL == pqueue) return false;
    
    if(queue_full(pqueue)) return false;
    
    unsigned free_len = queue_free(pqueue);
    
    if(data_len > free_len)
    {
        return false;
    }

    if(pqueue->tail > pqueue->head)
    {
        unsigned len = pqueue->size - pqueue->tail;
        if(len < data_len)
        {
            memcpy(pqueue->buff + pqueue->tail, data, len);
            len = data_len - len;
            memcpy(pqueue->buff, data, len);
            pqueue->tail = len;
            return true;
        }
    } 
    
    memcpy(pqueue->buff + pqueue->tail, data, data_len);
    pqueue->tail += data_len;
    return true;
}

// 取数据
unsigned output_queue_data(PQUEUE pqueue, void *data, unsigned data_len)
{
    if(NULL == pqueue) return 0;
    
    unsigned queue_buff_len = pqueue->size -1 - queue_free(pqueue);
    data_len = min(data_len, queue_buff_len);
    if((pqueue->head + data_len) <= pqueue->size)
    {
        memcpy(data, pqueue->buff, data_len);
    } else {
        unsigned len = pqueue->size - pqueue->head;
        memcpy(data, pqueue->buff + pqueue->head, len);
        data_len -= len;
        memcpy(data+len, pqueue->buff, data_len);
    }
    
    pqueue->head = (pqueue->head + data_len) & (pqueue->size - 1);
    return data_len;
}

int main( int argc, char *argv[] )
{
    PQUEUE pqueue = create_queue(1024);
    if(NULL == pqueue)
    {
        printf("创建队列失败!\n");
    }

    char data[] = "hello world";
    unsigned len = strlen(data);
    if(!input_queue_data(pqueue, data, len))
    {
        printf("插入失败!\n");
    }

    char buff[12] = {0};
    output_queue_data(pqueue, buff, len);
    printf("%s\n",data);

    free_queue(pqueue);
    return 0;
}