大道至简—循环队列

29 篇文章 0 订阅
17 篇文章 0 订阅

大道至简—循环队列

一、前言

​ 队列可能是大家学习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)]


四、往期精彩汇总

GDB 多线程之旅

肝!动态规划

C++使用锁注意事项

呕心沥血的递归

muduo源码剖析学习总结

windows程序崩溃调试终极武器


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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值