环形队列原理及基于C++的实现
一、环形队列的作用
在嵌入式软件中,环形队列的地位是非常重要的。由于经常需要用到串口、SPI等通讯接口,为了避免高速CPU等待低速通讯外设的情况出现,通常需要给通讯接口的数据发送和接收分配缓存,而这一缓存需要实现先入先出这一功能,而环形队列正好拥有这一功能。
二、环形队列的原理
环形队列任然是基于数组实现的,但是为了更加形象化的描述,我们用如下图表示:
- 图中有两个指针(其实就是两个变量,因为在这里有指示作用,所以这里理解为指针_writeIndex、_readIndex,一个指示队头,一个指示队尾。
- _writeIndex和_readIndex互相追赶着,这个追赶过程就是队列添加和删除的过程,如果_writeIndex追到_readIndex说明队列满了(通常会留一个位置),如果_readIndex追到_writeIndex说明队列为空。
- 我们把它掰弯,用的是求余,这样这两个值就不会跑出最大范围,并且可以实现首位连接的效果,所以说对于循环队列我们必须给定最大值MAXQSIZE。
三、环形队列的软件实现
#pragma once
#include <string.h>
template<typename T>
class RingQueue
{
public:
// 设置存储空间,及其大小。
void setBuff(T *buff, unsigned int len);
// 从尾部加入一个数据。
void push(T d);
// 从头部弹出一个数据。
T pop(void);
// 从头部弹出若干数据。
unsigned int copyOut(T *buf, unsigned int len);
// 从尾部加入若干数据。
unsigned int copyIn(T *buf, unsigned int len);
// 头部数据。
T head(bool &isok);
// 头部数据。
T head();
// 尾部数据。
T tail(bool &isok);
// 当前数据个数。
unsigned int size(void);
// 获取指定位置的数据。
T &at(int index);
// 空/满判断。
inline bool isEmpty(void);
inline bool isFull(void);
// 清空。
void clear(void);
// 构造与析构。
RingQueue();
virtual ~RingQueue();
private:
T *_buff;
unsigned int _len;
unsigned int _writeIndex;
unsigned int _readIndex;
};
/**************************************************************************************************
* 功能: 设置存储空间,及其大小。
* 参数:
* buff: 数据空间。
* len:数据空间长度。
*************************************************************************************************/
template<typename T>
void RingQueue<T>::setBuff(T *buff, unsigned int len)
{
_buff = buff;
_len = len;
_writeIndex = 0;
_readIndex = 0;
}
/**************************************************************************************************
* 功能: 从尾部加入一个数据。
* 参数:
* d: 新数据。
*************************************************************************************************/
template<typename T>
void RingQueue<T>::push(T d)
{
if (isFull())
{
return;
}
_buff[_writeIndex] = d;
_writeIndex = (_writeIndex + 1) % _len;
}
/**************************************************************************************************
* 功能: 从头部弹出一个数据。
* 返回:
* 头部数据。
*************************************************************************************************/
template<typename T>
T RingQueue<T>::pop(void)
{
if (isEmpty())
{
return 0;
}
T d = _buff[_readIndex];
_readIndex = (_readIndex + 1) % _len;
return d;
}
/**************************************************************************************************
* 功能:从头部弹出若干个数据
* 参数:
* buf: 用来接收数据的缓存
* len: 需要弹出的数据个数
* 返回:
* 实际弹出数据个数。
*************************************************************************************************/
template<typename T>
unsigned int RingQueue<T>::copyOut(T *buf, unsigned int len)
{
if (isEmpty())
{
return 0;
}
if(len > size())
{
len = size();
}
if(_readIndex + len > _len) // 分两段
{
memcpy(&buf[0], &_buff[_readIndex], (_len - _readIndex) * sizeof(T));
memcpy(&buf[_len - _readIndex], &_buff[0], (len + _readIndex - _len) * sizeof(T));
}
else // 一段
{
memcpy(&buf[0], &_buff[_readIndex], len * sizeof(T));
}
_readIndex = (_readIndex + len) % _len;
return len;
}
/**************************************************************************************************
* 功能:从尾部加入若干个数据
* 参数:
* buf: 用来接收数据的缓存
* len: 需要弹出的数据个数
* 返回:
* 实际加入数据个数。
*************************************************************************************************/
template<typename T>
unsigned int RingQueue<T>::copyIn(T *buf, unsigned int len)
{
if(len > _len - size() - 1)
{
len = _len - size() - 1;
}
if(_writeIndex + len > _len) // 分两段
{
memcpy(&_buff[_writeIndex], &buf[0], (_len - _writeIndex) * sizeof(T));
memcpy(&_buff[0], &buf[_len - _writeIndex], (len + _writeIndex - _len) * sizeof(T));
}
else // 一段
{
memcpy(&_buff[_writeIndex], &buf[0], len * sizeof(T));
}
_writeIndex = (_writeIndex + len) % _len;
return len;
}
/**************************************************************************************************
* 功能: 得到头部数据。
* 参数:
* isOK: 获取是否成功
* 返回:
* 头部数据。
*************************************************************************************************/
template<typename T>
T RingQueue<T>::head(bool &isOK)
{
if (isEmpty())
{
isOK = false;
return 0;
}
isOK = true;
return _buff[_readIndex];
}
/**************************************************************************************************
* 功能: 得到头部数据。
* 返回:
* 头部数据。
*************************************************************************************************/
template<typename T>
T RingQueue<T>::head()
{
return _buff[_readIndex];
}
/**************************************************************************************************
* 功能: 得到尾部数据。
* 参数:
* isOK: 获取是否成功
* 返回:
* 尾部数据。
*************************************************************************************************/
template<typename T>
T RingQueue<T>::tail(bool &isOK)
{
if (isEmpty())
{
isOK = false;
return 0;
}
isOK = true;
return _buff[(_writeIndex - 1 + _len) % _len];
}
/**************************************************************************************************
* 功能: 当前数据个数。
* 返回:
* 数据个数。
*************************************************************************************************/
template<typename T>
unsigned int RingQueue<T>::size(void)
{
unsigned int wi = _writeIndex;
unsigned int ri = _readIndex;
return (wi >= ri) ? (wi - ri) : (_len - ri + wi);
}
/**************************************************************************************************
* 功能: 获取指定位置的数据。
* 参数:
* index:数据位置。
* 返回:
* 指定位置的数据。
*************************************************************************************************/
template<typename T>
T &RingQueue<T>::at(int index)
{
return _buff[(_readIndex + index) % _len];
}
/**************************************************************************************************
* 功能: 是否空。
* 返回:
* true,空; false,非空。
*************************************************************************************************/
template<typename T>
inline bool RingQueue<T>::isEmpty(void)
{
return (_readIndex == _writeIndex);
}
/**************************************************************************************************
* 功能: 是否满。
* 返回:
* true,满; false,非满。
*************************************************************************************************/
template<typename T>
inline bool RingQueue<T>::isFull(void)
{
// 使用少存放一个数据的方式判断满。
unsigned int wi = _writeIndex;
unsigned int ri = _readIndex;
return ((wi + 1) % _len == ri);
}
/**************************************************************************************************
* 功能:清空。
*************************************************************************************************/
template<typename T>
void RingQueue<T>::clear(void)
{
_writeIndex = 0;
_readIndex = 0;
}
/**************************************************************************************************
* 功能:构造。
*************************************************************************************************/
template<typename T>
RingQueue<T>::RingQueue()
{
_buff = NULL;
_len = 0;
_writeIndex = 0;
_readIndex = 0;
}
/**************************************************************************************************
* 功能:析构。
*************************************************************************************************/
template<typename T>
RingQueue<T>::~RingQueue()
{
}