資料結構與演算法1 — 迴圈佇列
阿新 • • 發佈:2021-09-01
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; }