C ++简单循环缓冲区队列

时间:2017-05-05 13:10:53

标签: c++ queue

我使用数组实现了一个队列,并将其视为循环缓冲区。 _tail指向要读取的下一个元素,_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;
};

但是,我的isFull()isEmpty()逻辑中存在一个错误,该问题由以下问题确定:

当队列最初为空时,_tail_head都会指向_q[0]

当我写_q[0]时,_q[1]_q[2]q[3]再次_tail_head将指向相同,那么清楚我无法使用_tail == _head来确定完整/空。

实现isEmpty()isFull()逻辑的最简单方法是什么?我不确定我是否应该写一个&#34; BLANK&#34;读取队列项后的枚举?

4 个答案:

答案 0 :(得分:0)

在类中声明一个数据成员(计数器),用于计算队列中的项目数。递增(推)并递减(弹出)。当它为(0)时,队列为空

答案 1 :(得分:0)

如果您愿意将队列的有效大小减少一个元素,那么逻辑相对简单:

  • headtail相同时,队列为空。
  • 当将tail递增1时,使用环绕生成head,队列已满。

这使得不可能插入作为“哨兵”的第N个元素。因此,对于N元素队列,您需要分配一个N + 1个元素的数组,并在处理环绕的所有表达式中使用(SIZE+1)

std::array<int,SIZE+1> _q;

实施说明:

这两行

_head = ++_head % SIZE;
_tail = ++_tail % SIZE;  

具有未定义的行为,因为编译器可以灵活地应用在赋值结束之前或之后递增_head_tail的副作用。如果编译器选择在赋值后应用副作用,则不会发生环绕效果。

由于您根本不需要复合赋值,因此修复很简单:

_head = (_head+1) % SIZE;
_tail = (_tail+1) % SIZE;  

答案 2 :(得分:0)

如何更改实现有点像

从&#34; _head points to the next element to write into:&#34;更改您的头部定义到&#34; _head points to latest element added&#34;

然后isFull()可以是

bool isFull()
{
    if((_head + 1) % SIZE == _tail)
        return true;

    return false;
}

isEmpty可能是

bool isEmpty()
{
    if(_head == _tail)
        return true;

    return false;
}

pop()会相同但更改push()并且不要忘记将_head_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;
}

答案 3 :(得分:0)

由于您使用模数来计算数组的索引,因此保留每次读写的运行计数可以简化逻辑。

改变这样的实现......

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;
}