队列(Queue)是一种常见的数据结构,它遵循先进先出(FIFO)的原则,即最早进入队列的元素将最先被移除。队列在计算机科学中有广泛的应用,比如任务调度、网络流量控制、打印任务管理等。然而,当我们在处理固定大小的空间时,传统的队列实现可能会遇到空间浪费的问题。为了解决这个问题,我们引入了循环队列(Circular Queue)的概念。 关于队列的详细介绍,请参考前置文章 【数据结构与算法】使用单链表实现队列:原理、步骤与应用-CSDN博客
循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。相比于传统的队列实现,循环队列能够更有效地利用存储空间,并在数组大小固定的情况下实现队列的无限循环。在本文中,我们将详细探讨如何使用数组来实现循环队列,并分析其优势和应用场景。
循环队列的实现方式主要是基于数组的,但也可以采用其他数据结构,如链表。不过,在实际应用中,数组实现循环队列的方式更为常见和高效。
基于数组实现循环队列的特点和优势:
循环队列在逻辑上的结构是这样的
但在物理上的结构是这样的
包含
typedef int CQueueDataType;
typedef struct MyCircularQueue//循环队列结构定义
{
CQueueDataType* a;
int front;
int rear;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) //循环队列初始化
{
MyCircularQueue* tmp = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
tmp->a = (CQueueDataType*)malloc(sizeof(CQueueDataType) * (k + 1));
tmp->front = tmp->rear = 0;
tmp->k = k;
return tmp;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) //入队列
{
assert(obj);
if (myCircularQueueIsFull(obj))
return false;
obj->a[obj->rear] = value;
obj->rear = (obj->rear + 1) % (obj->k + 1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) //出队列
{
assert(obj);
if (myCircularQueueIsEmpty(obj))
return false;
obj->front = (obj->front + 1) % (obj->k + 1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) //取队首元素
{
assert(obj);
if (myCircularQueueIsEmpty(obj))
return -1;
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) //取队尾元素
{
assert(obj);
if (myCircularQueueIsEmpty(obj))
return -1;
return obj->a[(obj->rear - 1 + obj->k + 1) % (obj->k + 1)];
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) //判空
{
assert(obj);
return obj->front == obj->rear;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) //判满
{
assert(obj);
return (obj->rear + 1) % (obj->k + 1)==(obj->front);
}
void myCircularQueueFree(MyCircularQueue* obj) //循环队列销毁
{
free(obj->a);
obj->front = obj->rear = 0;
obj->k = 0;
free(obj);
obj = NULL;
}
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int CQueueDataType;
typedef struct MyCircularQueue//循环队列结构定义
{
CQueueDataType* a;
int front;
int rear;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k); //循环队列初始化
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value);//入队列
bool myCircularQueueDeQueue(MyCircularQueue* obj);//出队列
int myCircularQueueFront(MyCircularQueue* obj);//取队首元素
int myCircularQueueRear(MyCircularQueue* obj); //取队尾元素
bool myCircularQueueIsEmpty(MyCircularQueue* obj); //判空
bool myCircularQueueIsFull(MyCircularQueue* obj);//判满
void myCircularQueueFree(MyCircularQueue* obj); //循环队列销毁
#include"Circular_Queue.h"
MyCircularQueue* myCircularQueueCreate(int k) //循环队列初始化
{
MyCircularQueue* tmp = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
tmp->a = (CQueueDataType*)malloc(sizeof(CQueueDataType) * (k + 1));
tmp->front = tmp->rear = 0;
tmp->k = k;
return tmp;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) //入队列
{
assert(obj);
if (myCircularQueueIsFull(obj))
return false;
obj->a[obj->rear] = value;
obj->rear = (obj->rear + 1) % (obj->k + 1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) //出队列
{
assert(obj);
if (myCircularQueueIsEmpty(obj))
return false;
obj->front = (obj->front + 1) % (obj->k + 1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) //取队首元素
{
assert(obj);
if (myCircularQueueIsEmpty(obj))
return -1;
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) //取队尾元素
{
assert(obj);
if (myCircularQueueIsEmpty(obj))
return -1;
return obj->a[(obj->rear - 1 + obj->k + 1) % (obj->k + 1)];
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) //判空
{
assert(obj);
return obj->front == obj->rear;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) //判满
{
assert(obj);
return (obj->rear + 1) % (obj->k + 1)==(obj->front);
}
void myCircularQueueFree(MyCircularQueue* obj) //循环队列销毁
{
free(obj->a);
obj->front = obj->rear = 0;
obj->k = 0;
free(obj);
obj = NULL;
}
#include"Circular_Queue.h"
void test1()
{
int k = 0;
scanf("%d", &k);
MyCircularQueue* CQ = myCircularQueueCreate(k);//创建循环队列并初始化
if (myCircularQueueIsEmpty(CQ))
printf("队列空\n");
myCircularQueueEnQueue(CQ, 1);//插入五个数据
myCircularQueueEnQueue(CQ, 2);
myCircularQueueEnQueue(CQ, 3);
myCircularQueueEnQueue(CQ, 4);
myCircularQueueEnQueue(CQ, 5);
if (myCircularQueueIsEmpty(CQ))
printf("队列空\n");
else
printf("队列非空\n");
if (myCircularQueueIsFull(CQ))
printf("队列满\n");
else
printf("队列非满\n");
printf("队首元素:%d\n", myCircularQueueFront(CQ));
printf("队尾元素:%d\n", myCircularQueueRear(CQ));
while (!myCircularQueueIsEmpty(CQ))//依次打印队首元素并删除
{
printf("%d ", myCircularQueueFront(CQ));
myCircularQueueDeQueue(CQ);
}
printf("\n");
myCircularQueueFree(CQ);
}
int main()
{
test1();
return 0;
}
循环队列在实际应用中有着广泛的用途。以下是一些常见的应用场景:
循环队列是一种利用数组循环特性实现队列操作的数据结构。它通过维护头指针和尾指针来管理队列的入队和出队操作,实现了对固定大小空间的高效利用。 循环队列在任务调度、网络通信、打印机管理以及模拟系统等多个领域都有广泛的应用。 通过本文的介绍和分析,我们可以看到循环队列在解决实际问题时具有显著的优势和灵活性。因此,掌握循环队列的实现原理和应用方法对于提高编程能力和解决实际问题具有重要意义。