大道至简—循环队列
一、前言
队列可能是大家学习linux通讯时接触到的知识,当然也是我们在编程中使用较多的一个点,其中最主要的一方面用来降低程序之间的耦合度,还有异步操作;
前段时间在公司写了一个小的服务,同样使用了队列对服务进行了异步操作,知识队列没有使用现有的一些大型库,自己使用了原生的STL队列中的接口,进行了简单的封装,当前对代码调优不够,后来才发现有很多的漏洞影响着性能;其中就有一条是引发今天这篇文章的元素——在程序中,需要不断的申请释放内存,这样就影响了程序的性能;
使用循环队列就可以很轻松的解决上述问题,在程序开始的时候就申请内存,在程序结束的时候释放内存,这样就避免了程序不断的申请释放内存带来的消耗~
二、假溢出
“假溢出”是什么?其实用大白话来说就是明明还有空间可以存储数据,但是程序却告诉你你没有空间可以存储数据了!
案例:
比如一个队列que,头是front,尾是end,队列长度是L;当front等于-1时队空,rear等于L-1时为队满;队列一般是头部插入,尾部取出;当尾部等于L-1时,但是front不等于-1,这个队列并没有真正满载,所以就会造成假溢出,这个就是假溢出的来源~
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rzejEPLD-1600387183686)(https://imgkr2.cn-bj.ufileos.com/6639cbc9-4665-45c5-92d9-da468f32ed8b.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=biqQtNJL1yp7NJf61UsyYjZpgF0%253D&Expires=1600472606)]
解决:
其实类似这种情况的出现只有在规定链表长度的时候才会使用,一般我们编写队列的时候,在数据量不是特别大的时候,不会规定队列的大小,但是我们在特定情况下编写就需要考虑这种情况的发生~
- 使用循环队列;通过首位连接的方式,判断队列是否满
- 使用移动的方式,使队列平移
三、循环队列的实现
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fihEM1es-1600387183688)(https://imgkr2.cn-bj.ufileos.com/00cf17f1-e34a-48f3-b7cd-d7d7086b1f12.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=YbrxiLNHE9u8x3JTHCxB2yr%252BOJE%253D&Expires=1600472633)]
实现循环队列时需要注意判断循环队列是否满或者是否空,判断队列是否满有两种方法:
- 使用标志位判断循环队列是否为空
- 在循环队列下,仍定义front=rear时为队空,而判断队满则用两种办法,一是用“牺牲一个单元”,即rear+1=front(准确记是(rear+1)%m=front,m是队列容量)时为队满。
第二种方案其实需要判断多个条件,网上一些代码是有问题,希望火眼金睛~
这里使用的第一种使用标记的方式标记了队列空和满的方式:
代码实现以及测试:
cirque.h
#ifndef _CIRQUE_H_
#define _CIRQUE_H_
#include <iostream>
#include <queue>
using namespace std;
class CIRQUE
{
public:
CIRQUE(int size);
~CIRQUE();
//队列是否为空
bool IsEmpty();
//清空队列
void ClearQue();
//队列是否满
bool IsFull();
//入队操作
bool InsetQue(int val);
//出队操作
bool PopQue(int &val);
//获取当前循环队列中的元素
int getNumQue();
private:
int m_size;
//队列头
int m_head;
//队列尾
int m_tail;
//数组指针
int* m_pQue;
//队列数量
int m_QueNum;
//标志位--是否为空
bool bEmpty;
//标志位--是否满
bool bFull;
};
#endif
cirque.cpp
#include "cirque.h"
CIRQUE::CIRQUE(int size)
{
m_size = size;
m_pQue = new int[m_size];
ClearQue();
}
CIRQUE::~CIRQUE()
{
delete[] m_pQue;
m_pQue = NULL;
}
bool CIRQUE::IsEmpty()
{
return bEmpty;
}
void CIRQUE::ClearQue()
{
m_head = m_tail = 0;
m_QueNum = 0;
bEmpty = true;
bFull = false;
}
bool CIRQUE::IsFull()
{
return bFull;
}
bool CIRQUE::InsetQue(int val)
{
if (IsFull())
{
cout << "queue is full" << endl;
return false;
}
m_tail = (m_tail+1) % m_size;
m_pQue[m_tail] = val;
m_QueNum++;
bEmpty = false;
if (m_QueNum == m_size)
{
bFull = true;
}
return true;
}
bool CIRQUE::PopQue(int &val)
{
if (IsEmpty())
{
cout << "队列为空,不能出队" << endl;
return false;
}
m_QueNum--;
if (m_QueNum == 0)
{
bEmpty = true;
}
m_head = (m_head+1) % m_size;
val = m_pQue[m_head];
return true;
}
int CIRQUE::getNumQue()
{
return m_QueNum;
}
main.cpp
#include "cirque.h"
int main()
{
int val = 0;
CIRQUE CIR(4);
CIR.InsetQue(10);
CIR.InsetQue(11);
CIR.InsetQue(12);
CIR.PopQue(val);
CIR.InsetQue(17);
CIR.InsetQue(17);
CIR.InsetQue(17);
CIR.InsetQue(17);
cout << "val:"<<val << endl;
cout << "num:"<< CIR.getNumQue() << endl;
CIR.InsetQue(17);
return 0;
}
结果展示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7p5ba8kF-1600387183689)(https://imgkr2.cn-bj.ufileos.com/51386b25-a29a-40d6-b558-7ac2f7f86d86.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=Fa9bORc2gc4f38BCcXMViZ%252F2hQg%253D&Expires=1600472647)]
四、往期精彩汇总
欢迎关注公众号—后台服务器开发,更多精彩等你来看~