队列:
- 线性的集合。
- 先进先出(FIFO,first in first out)。
- 两个指针:头指针(指向第一个进入且第一个出去的元素),尾指针(指向最后一个进入且最后一个出去的元素)。
- 两个操作:入队(往队尾添加元素),出队(从队头删除元素)。
- 队列有优先队列,双端队列,循环队列等。
- 可以使用链表实现,也可以使用数组实现。本文使用数组实现循环队列。
添加元素:
往队尾添加。若尾指针已指向队尾,则循环重新指向队头。
删除元素:
从队头删除。若头指针已指向队尾,则循环重新指向队头。
扩容、缩容:
若内存区域已全部使用完,则增加内存区域。若内存区域使用小,则减少内存区域。
方法:新开辟内存区域,将原数据复制到新内存区域。
若头指针在尾指针的前面,则从头指针到尾指针的数据依次复制到新内存区域。
若尾指针在头指针的前面,则从头指针到内存区域最后的这m个数据,依次复制到新区域0到m-1,再从0到尾指针的数据,依次复制到n到n-1(n为实际存储数据个数)。
C语言实现:(使用数组实现循环队列)
创建结构体数据类型:
- 指针p:记录数组的内存地址(即数组第一个元素的地址)。
- 整型length:记录数组最大物理容量(即创建数组时指定的内存大小)。
- 整型n:记录数组实际逻辑大小(即数组实际已经存储的数据个数)。
- 指针front:头指针,始终指向数组数据中第一个进入且将第一个出去的元素。
- 指针rear:尾指针,始终指向数组数据中最后一个进入且将最后一个出去的元素。
typedef struct Queue
{int *p; // 数组内存地址int length; // 物理最大容量int n; // 实际存储数据int *front; // 始终指向第一个进入且第一个出去的元素int *rear; // 始终指向最后一个进入且最后一个出去的元素
} Queue; // 别名
创建队列变量:
Queue queue;
初始化队列:
void init(Queue *queue, int len)
{queue->p = (int *)malloc(len * sizeof(int)); // 分配数组内存空间if(queue->p == NULL){perror("Memory allocation failled");exit(-1);}queue->length = len; // 指定物理大小queue->n = 0; // 实际存储数据个数,初始化为0queue->front = queue->p; // 头指针,初始化指向数组第一个元素地址queue->rear = queue->p; // 尾指针,初始化指向数组第一个元素地址
}
扩容、缩容:
void resize(Queue *queue, int len)
{// 开辟新内存空间,将原数据复制到新地址int *t = (int *)malloc(len * sizeof(int));int *tmp = queue->front;// 若头指针在前,依次复制从头指针到尾指针的数据if(queue->front < queue->rear){for(int k = 0; k < queue->n; k++){t[k] = *tmp;tmp++;} }// 若尾指针在前,复制头指针到数组最后的数据,再复制数组开头到尾指针的数据else if(queue->front > queue->rear){int i;int m = queue->p + queue->n - queue->front;for(i = 0; i < m; i++){t[i] = *tmp;tmp++;}for(; i < queue->n; i++){t[i] = queue->p[i - m];}}queue->p = t;queue->length = len;queue->front = queue->p;queue->rear = queue->p + queue->n - 1;
}
添加元素:
往队尾添加。尾指针rear指向下一个元素。若尾指针已指向区域最后,则尾指针循环重新指向区域开头。
void add(Queue *queue, int data)
{if(queue->length == queue->n) // 若数组满,扩容{int newlength = queue->length * 2;resize(queue, newlength);}// 若尾指针指向数组最后,尾指针循环开始指向数组开头if(queue->rear == queue->p + queue->n) queue->rear = queue->p;else queue->rear++;*queue->rear = data;queue->n++;
}
删除元素:
从队头删除。头指针front指向下一个元素。若头指针已指向区域最后,则头指针循环重新指向区域开头。
int deltop(Queue *queue)
{int value = *queue->rear;queue->n--;// 若头指针已指向数组尾部,头指针循环开始指向数组开头if(queue->front == queue->p + queue->n) queue->front = queue->p;else queue->front++;if(queue->n < ceil(queue->length / 2) && queue->length > 4) // 满足条件,缩容{int newlength = ceil(queue->length / 2);resize(queue, newlength);}return value;
}
遍历队列元素:
void travel(Queue *queue)
{if(queue->n == 0) return ;printf("elements: ");int *tmp = queue->front;// 若头指针在前,依次从头指针遍历到尾指针if(queue->front < queue->rear){for(int k = 0; k < queue->n; k++){printf("%d ", *tmp);tmp++;} }// 若尾指针在前,遍历头指针到数组最后,再遍历数组开头到尾指针else if(queue->front > queue->rear){int i;int m = queue->p + queue->n - queue->front;for(i = 0; i < m; i++){printf("%d ", *tmp);tmp++;}for(; i < queue->n; i++){printf("%d ", queue->p[i - m]);}}printf("\n");
}
完整代码:(queue.c)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>/* structure */
typedef struct Queue
{int *p; // memory address of the queueint length; // maximum number of the queueint n; // actual number of the queueint *front; // point to the first elementint *rear; // point to the end element
} Queue;/* function prototype */
void init(Queue *, int); // queue initialization
void resize(Queue *, int); // increase or reduce the size of the queue
void add(Queue *, int); // add element to the end of the queue
int deltop(Queue *); // delete element from the start of the queue
void travel(Queue *); // show element one by one/* main function */
int main(void)
{Queue queue;init(&queue, 4);printf("length is %d, actual is %d\n", queue.length, queue.n);add(&queue, 8);add(&queue, 16);add(&queue, 23);printf("length is %d, actual is %d\n", queue.length, queue.n);travel(&queue);add(&queue, 65);printf("length is %d, actual is %d\n", queue.length, queue.n);travel(&queue);add(&queue, 27); // 已满,扩容printf("length is %d, actual is %d\n", queue.length, queue.n);travel(&queue);deltop(&queue);printf("length is %d, actual is %d\n", queue.length, queue.n);travel(&queue);deltop(&queue); // 使用少于一半,缩容printf("length is %d, actual is %d\n", queue.length, queue.n);travel(&queue);deltop(&queue);deltop(&queue);deltop(&queue);printf("length is %d, actual is %d\n", queue.length, queue.n);return 0;
}/* subfunction */
void init(Queue *queue, int len) // queue initialization
{queue->p = (int *)malloc(len * sizeof(int));if(queue->p == NULL){perror("Memory allocation failled");exit(-1);}queue->length = len;queue->n = 0;queue->front = queue->p;queue->rear = queue->p;
}void resize(Queue *queue, int len) // increase or reduce the size of the queue
{int *t = (int *)malloc(len * sizeof(int)); // new memory spaceint *tmp = queue->front; // copy datas to new memroy spaceif(queue->front < queue->rear){ // copy elements from front pointer to rear pointerfor(int k = 0; k < queue->n; k++){t[k] = *tmp;tmp++;} }else if(queue->front > queue->rear){int i;int m = queue->p + queue->n - queue->front;for(i = 0; i < m; i++){ // copy elements from front pointer to the end of the queuet[i] = *tmp;tmp++;}for(; i < queue->n; i++){ // copy elements from start of the queue to the rear pointert[i] = queue->p[i - m];}}queue->p = t;queue->length = len;queue->front = queue->p;queue->rear = queue->p + queue->n - 1;
}void add(Queue *queue, int data) // add element to the end of the queue
{if(queue->length == queue->n) // increase the size of the queue{int newlength = queue->length * 2;resize(queue, newlength);}// if rear point to the end space, rear point to index 0if(queue->rear == queue->p + queue->n) queue->rear = queue->p;else queue->rear++;*queue->rear = data;queue->n++;
}int deltop(Queue *queue) // delete element from the start of the queue
{int value = *queue->rear;queue->n--;// if front point to the end space,front point to index 0if(queue->front == queue->p + queue->n) queue->front = queue->p;else queue->front++;if(queue->n < ceil(queue->length / 2) && queue->length > 4) // reduce the size of the queue{int newlength = ceil(queue->length / 2);resize(queue, newlength);}return value;
}void travel(Queue *queue) // show element one by one
{if(queue->n == 0) return ;printf("elements: ");int *tmp = queue->front;if(queue->front < queue->rear){ // copy elements from front pointer to rear pointerfor(int k = 0; k < queue->n; k++){printf("%d ", *tmp);tmp++;} }else if(queue->front > queue->rear){int i;int m = queue->p + queue->n - queue->front;for(i = 0; i < m; i++){ // copy elements from front pointer to the end of the queueprintf("%d ", *tmp);tmp++;}for(; i < queue->n; i++){ // copy elements from start of the queue to the rear pointerprintf("%d ", queue->p[i - m]);}}printf("\n");
}
编译链接: gcc -o queue queue.c
执行可执行文件: ./queue