一、原理
循环队列从功能角度具有队列的性质,即遵从先进先出原则,但是其存储方式是顺序存储。
循环队列的存储空间大小通常都是固定的,通过前指针和尾指针的移动控制循环队列数据的增删。
特征:顺序存储、先进先出、容量有限(循环利用)
设计理念:
- 初始化一个队列空间(容量为C),这是循环队列能够存储数据的最大容量数
- 设置头指针front和尾指针rear,刚开始时front和rear指向同一个数据存储地址
- 新增数据,front不动,rear指向下一个数据存储地址
- 删除数据,rear不懂,front指向下一个数据存储地址
- 为了防止front和rear越界,front和rear在每次移动之后都会对容量C取模
当循环队列为空或为满的时候,front和rear都指向同一个位置,该如何区分呢?
- 在容量为C的队列空间中,取出一个数据块空间不存储数据,用于区分队列空和队列满
- 此空数据块位于front的后一个地址,当rear和front之间只相隔一个数据块,即规定的空数据块时,不再新增数据
- 随着队列前指针front移动,空数据块也跟着移动
二、CircularQueue.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#define CAPACITY 5
// 循环队列的容量,通常循环队列存储元素的个数为容量-1
typedef int DataType;
typedef struct CirQueue
{
DataType* data;
int front;
int rear;
}CirQueue;
void Init(CirQueue* cq)
{
cq->data = (DataType*)malloc(sizeof(DataType) * CAPACITY);
cq->front = cq->rear = 0;
}
int Empty(CirQueue* cq)
{
return cq->front == cq->rear;
}
int Full(CirQueue* cq)
{
return (cq->rear + 1) % CAPACITY == cq->front;
}
void Push(CirQueue* cq, DataType x)
{
if (Full(cq))
{
printf("循环队列已满,push失败\n");
return;
}
cq->data[cq->rear] = x;
cq->rear = (cq->rear + 1) % CAPACITY;
}
void Pop(CirQueue* cq)
{
if (Empty(cq))
{
printf("循环队列已空,pop失败\n");
return;
}
cq->front = (cq->front + 1) % CAPACITY;
}
int Size(CirQueue* cq)
{
return ((cq->rear + CAPACITY) - cq->front) % CAPACITY;
}
void Print(CirQueue* cq)
{
if (Empty(cq))
{
printf("循环队列为空\n ");
return;
}
int pos = cq->front;
while (pos != cq->rear)
{
printf("%2d ", cq->data[pos]);
pos = (pos + 1) % CAPACITY;
}
printf(",循环队列存储元素个数为:%d\n", Size(cq));
}
三、test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "CircularQueue.h"
int main()
{
CirQueue cq;
Init(&cq);
Push(&cq, 1);
Push(&cq, 3);
Push(&cq, 5);
Push(&cq, 7);
Push(&cq, 2);
Push(&cq, 4);
Push(&cq, 6);
Push(&cq, 8);
Print(&cq);
Pop(&cq);
Pop(&cq);
Print(&cq);
Push(&cq, 10);
Print(&cq);
Pop(&cq);
Pop(&cq);
Pop(&cq);
Pop(&cq);
Pop(&cq);
Print(&cq);
}