大道至简—循环队列

207 阅读3分钟

大道至简—循环队列

一、前言

​ 队列可能是大家学习linux通讯时接触到的知识,当然也是我们在编程中使用较多的一个点,其中最主要的一方面用来降低程序之间的耦合度,还有异步操作;

​ 前段时间在公司写了一个小的服务,同样使用了队列对服务进行了异步操作,知识队列没有使用现有的一些大型库,自己使用了原生的STL队列中的接口,进行了简单的封装,当前对代码调优不够,后来才发现有很多的漏洞影响着性能;其中就有一条是引发今天这篇文章的元素——在程序中,需要不断的申请释放内存,这样就影响了程序的性能;

​ 使用循环队列就可以很轻松的解决上述问题,在程序开始的时候就申请内存,在程序结束的时候释放内存,这样就避免了程序不断的申请释放内存带来的消耗~

二、假溢出

“假溢出”是什么?其实用大白话来说就是明明还有空间可以存储数据,但是程序却告诉你你没有空间可以存储数据了!

案例:

比如一个队列que,头是front,尾是end,队列长度是L;当front等于-1时队空,rear等于L-1时为队满;队列一般是头部插入,尾部取出;当尾部等于L-1时,但是front不等于-1,这个队列并没有真正满载,所以就会造成假溢出,这个就是假溢出的来源~

![](https://imgkr2.cn-bj.ufileos.com/6639cbc9-4665-45c5-92d9-da468f32ed8b.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=biqQtNJL1yp7NJf61UsyYjZpgF0%253D&Expires=1600472606)

解决:

其实类似这种情况的出现只有在规定链表长度的时候才会使用,一般我们编写队列的时候,在数据量不是特别大的时候,不会规定队列的大小,但是我们在特定情况下编写就需要考虑这种情况的发生~

  • 使用循环队列;通过首位连接的方式,判断队列是否满
  • 使用移动的方式,使队列平移

三、循环队列的实现

![](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;}

结果展示:

![](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)

四、往期精彩汇总

GDB 多线程之旅

肝!动态规划

C++使用锁注意事项

呕心沥血的递归

muduo源码剖析学习总结

windows程序崩溃调试终极武器

欢迎关注公众号---后台服务器开发,更多精彩等你来看~