队列:
- 线性的集合。
- 先进先出(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; // 实际存储数据个数,初始化为0
queue->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 queue
int length; // maximum number of the queue
int n; // actual number of the queue
int *front; // point to the first element
int *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 space
int *tmp = queue->front; // copy datas to new memroy space
if(queue->front < queue->rear)
{ // copy elements from front pointer to rear pointer
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++)
{ // copy elements from front pointer to the end of the queue
t[i] = *tmp;
tmp++;
}
for(; i < queue->n; i++)
{ // copy elements from start of the queue to the rear pointer
t[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 0
if(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 0
if(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 pointer
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++)
{ // copy elements from front pointer to the end of the queue
printf("%d ", *tmp);
tmp++;
}
for(; i < queue->n; i++)
{ // copy elements from start of the queue to the rear pointer
printf("%d ", queue->p[i - m]);
}
}
printf("\n");
}
编译链接: gcc -o queue queue.c
执行可执行文件: ./queue