循环队列的API设计与应用
什么是循环队列?循环队列有什么用?
循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首以形成一个循环。它也被称为“环形队列”。循环队列在内存中是一个首尾相接的环状空间,这个环状空间可以由数组来模拟。
循环队列的主要目的是为了更好地利用资源,克服假溢出的问题。在普通队列中,当队列为空时,front=rear;而当队列满时,也仍有front=rear。为了区分队列满还是队列空,有三种方式:一种是浪费一个存储空间,约定队列满时,保留一个空闲单元;第二种方式是设置一个表示队列元素个数的数据成员;第三种方式就是使用循环队列。
循环队列的优点主要体现在以下几个方面:
- 无空间浪费:由于循环队列首尾相接,因此可以充分利用存储空间,避免浪费。
- 操作方便:循环队列的入队和出队操作都可以通过简单的指针移动实现,易于理解和实现。
下面是一个简单的循环队列的例子:
假设我们有一个大小为5的循环队列,用数组queue[5]
来表示。我们用两个指针front
和rear
来分别表示队列的头部和尾部。初始时,front = rear = 0
。
- 入队操作:当我们要将一个元素入队时,首先检查队列是否已满(即
(rear + 1) % 5 == front
)。如果队列未满,则将元素放入queue[rear]
的位置,并将rear
指针向后移动一位(即rear = (rear + 1) % 5
)。 - 出队操作:当我们要将一个元素出队时,首先检查队列是否为空(即
front == rear
)。如果队列不为空,则取出queue[front]
位置的元素,并将front
指针向后移动一位(即front = (front + 1) % 5
)。
通过循环队列,我们可以有效地管理和操作队列数据,避免了空间的浪费,并使得队列的操作更加高效和便捷
例子?
在项目中,经常会有网络消息处理。在APP点击一个button,可能会触发APP通过网络发送几则消息给摄像头。这个时候,IPC需要处理这几则或者十几则消息。如果,IPC处理消息不是并发的,那么就需要不断接收,不断处理。这时候,运用队列的机制,可以让先接收到的消息先处理。而后接收的消息则等待,典型的先进先出原则。比如串口收发数据。
API函数声明
*********************************************************************************************************/
void InitQueue(StructCirQue* pQue, DATA_TYPE* pBuf, i16 len); //初始化队列
void ClearQueue(StructCirQue* pQue); //清队列
u8 QueueEmpty(StructCirQue* pQue); //判断队列是否为空,1-空,0-非空
i16 QueueLength(StructCirQue* pQue); //返回队列中元素个数,即为队列的长度
i16 EnQueue(StructCirQue* pQue, DATA_TYPE* pInput, i16 len); //入队len个元素
i16 DeQueue(StructCirQue* pQue, DATA_TYPE* pOutput, i16 len); //出队len个元素
void main(void)
{
StructCirQue cirQueForTest; //循环队列中
DATA_TYPE i;
DATA_TYPE bufForTest[30]; //循环队列中的buffer,可容纳30个元素
i16 len; //长度
DATA_TYPE arrBufForOutput[30]; //从队列取出的数据放入此数组
DATA_TYPE arrBufForInput[60]; //入队的数据先放到此处
DATA_TYPE dataForTest; //便于printf调用
for(i = 0; i < 60; i++)
{
arrBufForInput[i] = 60 + i * 2 + 1;
}
for(i = 0; i < 30; i++)
{
arrBufForOutput[i] = 0;
}
InitQueue(&cirQueForTest, bufForTest, 30);
//入队16个数据
printf("**************TEST1-入队16个数据******************\n");
EnQueue(&cirQueForTest, arrBufForInput, 16);
for(i = 0; i < 30; i++)
{
dataForTest = cirQueForTest.pBuffer[i];
printf("addr=%d, dataInput=%d\n", i, dataForTest);
}
//出队25个数据,实际只能出对16个数据
printf("**************TEST2-出队25个数据,实际只能出对16个数据******************\n");
len = DeQueue(&cirQueForTest, arrBufForOutput, 25);
printf("Num of DeQueue: %d\n", len);
for(i = 0; i < len; i++)
{
printf("i=%d, dataOuput=%d\n", i, arrBufForOutput[i]);
}
//入队20个数据
printf("**************TEST3-入队20个数据******************\n");
len = EnQueue(&cirQueForTest, &arrBufForInput[20], 20);
printf("Num of EnQueue: %d\n", len);
for(i = 0; i < 30; i++)
{
dataForTest = cirQueForTest.pBuffer[i];
printf("addr=%d, dataInput=%d\n", i, dataForTest);
}
//出队20个数据
printf("**************TEST4-出队20个数据******************\n");
len = DeQueue(&cirQueForTest, arrBufForOutput, 20);
printf("Num of DeQueue: %d\n", len);
for(i = 0; i < len; i++)
{
printf("i=%d, dataOuput=%d\n", i, arrBufForOutput[i]);
}
system("pause");
}