【问题标题】:C++ Create fixed size queueC++ 创建固定大小的队列
【发布时间】:2019-10-13 12:38:37
【问题描述】:

C++中,如何创建一个简单的固定大小队列

我在 Java 和 Python 中做过多次,但我正在寻找一种基于 C++ 的方法。

我需要一个只有 2 个元素的简单 FIFO 队列才能使用 pushpop 实用程序:我已经意识到我可以实现自己的类来执行这种限制,但我的问题旨在了解是否存在任何可用的解决方案。

或者是否有可能使用数组完成相同的任务?那也行。

【问题讨论】:

  • 你必须实现所需的受限容器并使用std::queue适配器。
  • @S.M.谢谢,你能详细说明一下吗?
  • 您必须在容器中至少实现push_backpop_frontsize 方法并在std::queue 中使用它。

标签: c++ queue


【解决方案1】:

你可以继承队列,然后重新实现 push 方法。这是一个基本示例。

#include <queue>
#include <deque>
#include <iostream>

template <typename T, int MaxLen, typename Container=std::deque<T>>
class FixedQueue : public std::queue<T, Container> {
public:
    void push(const T& value) {
        if (this->size() == MaxLen) {
           this->c.pop_front();
        }
        std::queue<T, Container>::push(value);
    }
};

int main() {
    FixedQueue<int, 3> q;
    q.push(1);
    q.push(2);
    q.push(3);
    q.push(4);
    q.push(5);
    q.push(6);
    q.push(7);

    while (q.size() > 0)
    {
        std::cout << q.front() << std::endl;
        q.pop();
    }
}

这将打印出来

$ g++ fixedqueue.cpp -std=c++17 -o fixedqueue && ./fixedqueue
5
6
7

【讨论】:

    【解决方案2】:

    在 C++ 中,如何创建一个简单的固定大小队列

    首先,我认为您真正想要的是一个固定容量队列,即队列的大小本身将受限于队列的容量,但大小可能会有所不同。例如,如果队列为空,则大小最初可以为零,并在您将元素插入队列时增加到队列的容量。


    使用boost::circular_buffer

    Boost 库具有库 Boost.CircularBuffer,它实现了 boost::circular_buffer 容器 (boost/circular_buffer.hpp)。该容器适合作为固定容量的 FIFO。

    std::vector 不同,boost::circular_buffer容量 保持不变,无论您向容器中插入多少元素。也就是说,不会在后台发生重新分配:如果 boost::circular_buffersize 达到其 容量,则插入新元素只会覆盖现有元素。

    您可以在构造时指定boost::circular_buffer的容量:

    boost::circular_buffer<int> cb(2);
    

    cb 的容量为2,由于容器为空,其初始大小为零。它的大小永远不能超过它的容量。但是,您可以显式更改容器的容量,例如,通过调用 circular_buffer::set_capacity()

    通过使用push_back()pop_front() 成员函数,您可以将boost::circular_buffer 用作FIFO。示例:

    #include <boost/circular_buffer.hpp>
    #include <iostream>
    
    void print(const boost::circular_buffer<int>& cb) {
       std::cout << "size: " << cb.size() << ", capacity: " << cb.capacity() << '\n';
    
       for (auto const& elem: cb)
          std::cout << elem << ' ';
       std::cout << '\n';
    }
    
    auto main() -> int {
       // empty: size is zero
       boost::circular_buffer<int> cb(3);
       print(q);
    
       cb.push_back(0);
       print(cb);
    
       cb.push_back(1);
       print(cb);
    
       cb.push_back(2);  
       print(cb);
    
       // overwrites the oldest element: 0
       cb.push_back(3);
       print(cb);
    
       // overwrites the oldest element: 1
       cb.push_back(4);
       print(cb);
    
       cb.pop_front();
       print(cb);
    
       cb.pop_front();
       print(cb);
    
       // empty again
       cb.pop_front();
       print(cb);
    }
    

    输出:

    size: 0, capacity: 3
    
    size: 1, capacity: 3
    0
    size: 2, capacity: 3
    0 1
    size: 3, capacity: 3
    0 1 2
    size: 3, capacity: 3
    1 2 3
    size: 3, capacity: 3
    2 3 4
    size: 2, capacity: 3
    3 4
    size: 1, capacity: 3
    4
    size: 0, capacity: 3
    

    使用std::queueboost::circular_buffer

    std::queue 是一个容器适配器,其底层容器默认为std::deque。但是,您可以将boost::circular_buffer 用作std::queue 的底层容器,因为它实现了front()back()push_back()pop_front() 成员函数:

    #include <queue>
    #include <boost/circular_buffer.hpp>
    #include <cassert>
    
    template<typename T>
    using FixedCapacityQueue = std::queue<T, boost::circular_buffer<T>>;
    
    auto main() -> int {
       FixedCapacityQueue<int> fixedCapQueue(boost::circular_buffer<int>(3));
    
       fixedCapQueue.push(0);
       fixedCapQueue.push(1);
       fixedCapQueue.push(2);
       fixedCapQueue.push(3); // overwrites the 0
       assert(fixedCapQueue.front() == 1);
    
       fixedCapQueue.pop(); // pops the 1
       assert(fixedCapQueue.front() == 2); 
    }
    

    【讨论】:

      【解决方案3】:

      使用循环自定义容器。在线示例在这里:https://ideone.com/0nEBZa

      #include <array>
      #include <iostream>
      #include <queue>
      
      template <typename T, size_t N = 2>
      class CyclicArray {
       public:
        typedef typename std::array<T, N>::value_type value_type;
        typedef typename std::array<T, N>::reference reference;
        typedef typename std::array<T, N>::const_reference const_reference;
        typedef typename std::array<T, N>::size_type size_type;
      
        ~CyclicArray() {
          while (size())
            pop_front();
        }
      
        void push_back(const T& v) {
          if (size_ + 1 > N)
            throw;
          new (&array_[(front_ + size_) % N]) T(v);
          ++size_;
        }
      
        void pop_front() {
          if (size_ < 1)
            throw;
          front().~T();
          ++front_;
          --size_;
          if (front_ >= N)
            front_ = 0;
        }
      
        const_reference front() const {
          return *reinterpret_cast<const T*>(&array_[front_]);
        }
      
        reference front() {
          return *reinterpret_cast<T*>(&array_[front_]);
        }
      
        size_type size() const {
          return size_;
        }
      
       private:
        size_type front_ = 0;
        size_type size_ = 0;
        std::array<char[sizeof(T)], N> array_;
      };
      
      int main() {
          std::queue<int, CyclicArray<int, 2>> queue;
          queue.push(1);
          queue.push(2);
          queue.pop();
          queue.push(3);
          int f = queue.front();
          queue.pop();
          std::cout << f << std::endl;
          f = queue.front();
          queue.pop();
          std::cout << f << std::endl;
          return 0;
      }
      

      输出

      2
      3
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-02-16
        • 1970-01-01
        • 2016-07-19
        • 1970-01-01
        • 1970-01-01
        • 2011-12-05
        • 2011-01-09
        相关资源
        最近更新 更多