C++ C++;简单循环缓冲队列
我使用数组实现了一个队列,并将其视为循环缓冲区C++ C++;简单循环缓冲队列,c++,queue,C++,Queue,我使用数组实现了一个队列,并将其视为循环缓冲区\u tail指向下一个要读取的元素,\u head指向下一个要写入的元素: template<int SIZE> class Q { bool push(const int item){ if(false == isFull()){ _q[_head] = item; _head = ++_head % SIZE; return true; } return f
\u tail
指向下一个要读取的元素,\u head
指向下一个要写入的元素:
template<int SIZE>
class Q {
bool push(const int item){
if(false == isFull()){
_q[_head] = item;
_head = ++_head % SIZE;
return true;
}
return false;
}
bool pop(int& toReturn){
if(false == isEmpty()){
toReturn = _q[_tail];
_tail = ++_tail % SIZE;
return true;
}
return false;
}
private:
std::array<int, SIZE> _q;
std::atomic<int> _head;
std::atomic<int> _tail;
};
模板
Q类{
布尔推送(常量整数项){
如果(false==isFull()){
_q[_head]=项目;
_头部=++\头部大小百分比;
返回true;
}
返回false;
}
布尔波普(内翻和内翻){
if(false==isEmpty()){
toReturn=_q[_tail];
_尾=++_尾%大小;
返回true;
}
返回false;
}
私人:
std::数组q;
标准:原子头;
std::原子尾;
};
但是,我的isFull()
和isEmpty()
逻辑中有一个bug,由以下问题确定:
当队列最初为空时,\u tail
和\u head
都将指向\u q[0]
当我写了\u q[0]
,\u q[1]
,\u q[2]
和q[3]
之后,再次\u tail
和\u head
将指向同一个,因此显然我不能使用\u tail
=\u head
来确定满/空
实现
isEmpty()
和isFull()逻辑的最简单方法是什么?我不确定是否应该在读取队列项目后写入“空白”枚举?在类中声明一个数据成员(计数器),该类统计队列中的项目数。递增(按)和递减(按)。当它为(0)时,队列为空如果您愿意将队列的有效大小减少一个元素,则逻辑相对简单:
- 当
head
和tail
相同时,队列为空
- 将
tail
增加1时,使用环绕,产生head
,队列已满
这使得不可能插入第N个元素,作为“哨兵”。因此,对于一个N元素队列,您需要分配一个N+1元素的数组,并在所有处理环绕的表达式中使用(SIZE+1)
std::array<int,SIZE+1> _q;
具有未定义的行为,因为编译器可以灵活地应用在赋值结束之前或之后递增\u head
和\u tail
的副作用。如果编译器选择在赋值后应用副作用,则不会发生环绕效应
由于您根本不需要复合赋值,因此修复非常简单:
_head = (_head+1) % SIZE;
_tail = (_tail+1) % SIZE;
将实现更改为类似的方式如何
将头的定义从“\u头指向下一个要写入的元素:
”更改为“\u头指向最新添加的元素”
”
然后可以使用isFull()
bool isFull()
{
if((_head + 1) % SIZE == _tail)
return true;
return false;
}
而isEmpty
可能是
bool isEmpty()
{
if(_head == _tail)
return true;
return false;
}
pop()
将是相同的,但更改为push()
,不要忘记将\u head
和\u tail
初始化为-1
bool push(const int item){
if(false == isFull()){
if(_head == -1) //If adding the first element,
_tail = 0; // tail will point to it as it was inititiallty 0
_head = ++_head % SIZE;
_q[_head] = item;
return true;
}
return false;
}
由于您使用模来计算数组的索引,因此为每次读写保留一个运行计数可能会简化逻辑
像这样更改实现
bool push(const int item){
if(false == isFull()){
_q[_head % SIZE] = item;
++_head;
return true;
}
return false;
}
bool pop(int& toReturn){
if(false == isEmpty()){
toReturn = _q[_tail % SIZE];
++_tail;
return true;
}
return false;
}
用这些
bool isFull()
{
return _head - _tail == SIZE;
}
bool isEmpty()
{
if (_head == _tail)
{
_head = _tail = 0;
return true;
}
return false;
}
我发现用\u head=\u tail=-1
来表示空虚是最简单的。您不必保留额外的变量,其余的逻辑也保持不变。
bool isFull()
{
return _head - _tail == SIZE;
}
bool isEmpty()
{
if (_head == _tail)
{
_head = _tail = 0;
return true;
}
return false;
}