1. 程式人生 > 其它 >資料結構與演算法1 — 迴圈佇列

資料結構與演算法1 — 迴圈佇列

1.queue.h 標頭檔案

#ifndef queue_H
#define queue_H

#include <stddef.h>

//迴圈佇列,內部結構為陣列,提供先進先出的資料訪問方式,支援多種資料型別,包括:int、struct等
typedef struct
{
    void *data;      //陣列
    size_t dataSize; //元素大小(位元組)
    size_t front;    //隊頭
    size_t rear;     //隊尾
    size_t capacity; //佇列容量
} Queue;

//定義該巨集可以直觀的看出佇列元素的資料型別,比如:Queue(int)
#define Queue(type) Queue #ifdef __cplusplus extern "C" { #endif int queue_init(Queue *queue, size_t dataSize, size_t capacity); void queue_free(Queue *queue); void queue_clear(Queue *queue); int queue_expand(Queue *queue, size_t increment); int queue_shrink(Queue *queue); size_t queue_length(
const Queue *queue); int queue_full(const Queue *queue); int queue_empty(const Queue *queue); int queue_push(Queue *queue, const void *data); int queue_pop(Queue *queue, void *data); int queue_insert(Queue *queue, const void *data, size_t offset); void *queue_front(const Queue *queue);
void *queue_rear(const Queue *queue); #ifdef __cplusplus } #endif #endif

2.queue.c 原始檔

#include "queue.h"
#include <string.h>
#include <stdlib.h>

//初始化
int queue_init(Queue *queue, size_t dataSize, size_t capacity)
{
    if (queue == NULL || dataSize <= 0 || capacity <= 0)
        return -1;

    capacity = capacity + 1; //rear始終指向隊尾的下一個元素,即容量要多一個
    queue->data = malloc(capacity * dataSize);
    if (queue->data == NULL)
        return -1;

    memset(queue->data, 0, capacity * dataSize);
    queue->front = 0;
    queue->rear = 0;
    queue->capacity = capacity;
    queue->dataSize = dataSize;
    return 0;
}

//釋放記憶體
void queue_free(Queue *queue)
{
    if (queue == NULL)
        return;

    if (queue->data != NULL)
    {
        free(queue->data);
        queue->data = NULL;
    }

    queue->front = 0;
    queue->rear = 0;
    queue->capacity = 0;
    queue->dataSize = 0;
}

//清空佇列
void queue_clear(Queue *queue)
{
    if (queue == NULL)
        return;

    if (queue->data != NULL)
        memset(queue->data, 0, queue->capacity * queue->dataSize);

    queue->front = 0;
    queue->rear = 0;
}

//擴充佇列
int queue_expand(Queue *queue, size_t increment)
{
    if (queue == NULL || increment <= 0)
        return -1;

    void *data = realloc(queue->data, (queue->capacity + increment) * queue->dataSize);
    if (data == NULL)
        return -1;

    queue->data = data;

    //移動元素,重新調整隊尾
    if (queue->front > queue->rear)
    {
        /* if (queue->rear > 0)
        {
            if (queue->rear <= increment) //擴充的容量足夠調整隊尾
            {
                memmove((char *)queue->capacity, (char *)queue->data, queue->rear * queue->dataSize);
                queue->rear = (queue->rear + queue->capacity) % (queue->capacity + increment);
            }
            else
            {
                //移動increment個元素到末尾
                memmove((char *)queue->capacity, (char *)queue->data, increment * queue->dataSize);
                //剩餘(queue->rear - increment)個元素移動到起始
                memmove((char *)queue->data, (char *)queue->data + increment * queue->dataSize, (queue->rear - increment) * queue->dataSize);
                queue->rear = queue->rear - increment;
            }
        }
        else
        {
            queue->rear = queue->capacity; //剛好在第一個位置時,不需要移動元素,修改隊尾即可
        }

        queue->capacity += increment; */

        //簡單的寫法
        size_t rear_old = queue->rear;
        queue->rear = queue->capacity;
        queue->capacity += increment;

        size_t i;
        for (i = 0; i < rear_old; i++) //將rear_old個元素移動到新分配的記憶體上
        {
            memmove((char *)queue->data + queue->rear * queue->dataSize, (char *)queue->data + i * queue->dataSize, queue->dataSize);
            queue->rear = (queue->rear + 1) % queue->capacity;
        }
    }
    else
    {
        queue->capacity += increment;
    }

    return 0;
}

//收縮佇列
int queue_shrink(Queue *queue)
{
    if (queue == NULL)
        return -1;

    if (queue_full(queue))
        return -1;

    if (queue->rear < queue->front)
        return -1;

    size_t capacity;
    if (queue_empty(queue)) //queue->rear == queue->front
        capacity = 2;       //如果佇列為空,收縮到最小容量2
    else
        capacity = queue->rear + 1; //前提:queue->rear > queue->front

    //隊尾大於對頭時才可以進行收縮
    void *data = realloc(queue->data, capacity * queue->dataSize);
    if (data == NULL)
        return -1;

    queue->data = data;
    queue->capacity = capacity;
    return 0;
}

//獲取佇列長度
size_t queue_length(const Queue *queue)
{
    if (queue == NULL || queue->data == NULL)
        return 0;

    return (queue->rear - queue->front + queue->capacity) % queue->capacity;
}

//判斷佇列是否已滿
int queue_full(const Queue *queue)
{
    if (queue == NULL)
        return -1;

    return (queue->rear + 1) % queue->capacity == queue->front;
}

//判斷佇列是否為空
int queue_empty(const Queue *queue)
{
    if (queue == NULL)
        return 1;

    return queue->rear == queue->front;
}

//入佇列
int queue_push(Queue *queue, const void *data)
{
    if (queue == NULL)
        return -1;

    if (queue_full(queue)) //佇列滿
        return -1;

    memcpy((char *)queue->data + queue->rear * queue->dataSize, data, queue->dataSize);
    queue->rear = (queue->rear + 1) % queue->capacity;
    return 0;
}

//出佇列
int queue_pop(Queue *queue, void *data)
{
    if (queue == NULL)
        return -1;

    if (queue_empty(queue)) //佇列空
        return -1;

    if (data != NULL)
        memcpy(data, (char *)queue->data + queue->front * queue->dataSize, queue->dataSize);

    queue->front = (queue->front + 1) % queue->capacity;
    return 0;
}

//插隊,offset為相對隊頭的偏移量
int queue_insert(Queue *queue, const void *data, size_t offset)
{
    if (queue == NULL)
        return -1;

    if (queue_full(queue)) //佇列滿
        return -1;

    size_t pos = (queue->front + offset) % queue->capacity; //插入位置
    //超過隊尾,或者佇列為空,直接入佇列
    if (pos >= queue->rear && (queue->rear >= queue->front || (queue->rear < queue->front && pos < queue->front)))
    {
        memcpy((char *)queue->data + queue->rear * queue->dataSize, data, queue->dataSize);
        queue->rear = (queue->rear + 1) % queue->capacity;
        return 0;
    }

    //元素後移
    size_t rear = queue->rear;
    void *ptr_rear_front; //rear的前一個元素
    while (rear != pos)
    {
        ptr_rear_front = (char *)queue->data + ((rear - 1 + queue->capacity) % queue->capacity) * queue->dataSize;
        memcpy((char *)queue->data + rear * queue->dataSize, ptr_rear_front, queue->dataSize);
        rear = (rear - 1 + queue->capacity) % queue->capacity;
    }

    //插入資料
    memcpy((char *)queue->data + pos * queue->dataSize, data, queue->dataSize);
    queue->rear = (queue->rear + 1) % queue->capacity;
    return 0;
}

//獲取隊頭元素指標
void *queue_front(const Queue *queue)
{
    if (queue == NULL)
        return NULL;

    if (queue_empty(queue)) //佇列空
        return NULL;

    return (char *)queue->data + queue->front * queue->dataSize;
}

//獲取隊尾元素指標
void *queue_rear(const Queue *queue)
{
    if (queue == NULL)
        return NULL;

    if (queue_empty(queue)) //佇列空
        return NULL;

    return (char *)queue->data + ((queue->rear - 1 + queue->capacity) % queue->capacity) * queue->dataSize;
}